locusing 0.1.2 → 0.1.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.
package/dist/index.mjs CHANGED
@@ -1,33 +1,14 @@
1
- import {
2
- init_render_svg,
3
- renderToSVG,
4
- toSVGString
5
- } from "./chunk-3XW6GBD6.mjs";
6
- import {
7
- ClockwiseTransform,
8
- CounterclockwiseTransform,
9
- Morphing,
10
- MoveToTarget,
11
- ReplacementTransform,
12
- Timeline,
13
- Transform,
14
- TransformFromCopy,
15
- TransformMatchingShapes,
16
- TransformMatchingTex,
17
- createTimeline,
18
- easingMap,
19
- getGSAPEasing,
20
- init_timeline,
21
- querySelectorAllIncludingSelf
22
- } from "./chunk-HNU2F3GX.mjs";
23
1
  import {
24
2
  __esm,
25
3
  __export,
26
4
  __objRest,
27
5
  __spreadProps,
28
6
  __spreadValues,
29
- __toCommonJS
30
- } from "./chunk-TQQRYA5H.mjs";
7
+ __toCommonJS,
8
+ init_render_svg,
9
+ renderToSVG,
10
+ toSVGString
11
+ } from "./chunk-VPKI3XSA.mjs";
31
12
 
32
13
  // src/math/complex.ts
33
14
  function complexToVector(z) {
@@ -481,8 +462,199 @@ var init_frame = __esm({
481
462
  }
482
463
  });
483
464
 
484
- // src/core/animate-proxy.ts
465
+ // src/animate/timeline.ts
485
466
  import { gsap } from "gsap";
467
+ function createTimeline(options) {
468
+ return new Timeline(options);
469
+ }
470
+ function getGSAPEasing(easing2) {
471
+ return easingMap[easing2] || easing2;
472
+ }
473
+ var Timeline, easingMap;
474
+ var init_timeline = __esm({
475
+ "src/animate/timeline.ts"() {
476
+ "use strict";
477
+ Timeline = class {
478
+ constructor(options = {}) {
479
+ this._status = "pending";
480
+ this.timeline = gsap.timeline({
481
+ paused: true,
482
+ onStart: () => {
483
+ var _a;
484
+ this._status = "running";
485
+ (_a = options.onStart) == null ? void 0 : _a.call(options);
486
+ },
487
+ onComplete: () => {
488
+ var _a;
489
+ this._status = "completed";
490
+ (_a = options.onComplete) == null ? void 0 : _a.call(options);
491
+ },
492
+ onUpdate: () => {
493
+ var _a;
494
+ (_a = options.onUpdate) == null ? void 0 : _a.call(options, this.progress);
495
+ }
496
+ });
497
+ }
498
+ /** 当前状态 */
499
+ get status() {
500
+ return this._status;
501
+ }
502
+ /** 当前进度 (0-1) */
503
+ get progress() {
504
+ return this.timeline.progress();
505
+ }
506
+ /** 总时长 */
507
+ get duration() {
508
+ return this.timeline.duration();
509
+ }
510
+ /** 当前时间 */
511
+ get time() {
512
+ return this.timeline.time();
513
+ }
514
+ /**
515
+ * 添加动画到时间线
516
+ */
517
+ add(target, vars, position) {
518
+ this.timeline.to(target, vars, position);
519
+ return this;
520
+ }
521
+ /**
522
+ * 添加回调函数
523
+ */
524
+ call(callback, position) {
525
+ this.timeline.call(callback, void 0, position);
526
+ return this;
527
+ }
528
+ /**
529
+ * 添加延迟
530
+ */
531
+ delay(seconds, position) {
532
+ this.timeline.to({}, { duration: seconds }, position);
533
+ return this;
534
+ }
535
+ /**
536
+ * 添加标签
537
+ */
538
+ label(name, position) {
539
+ this.timeline.addLabel(name, position);
540
+ return this;
541
+ }
542
+ /**
543
+ * 播放
544
+ */
545
+ play() {
546
+ this._status = "running";
547
+ this.timeline.play();
548
+ return this;
549
+ }
550
+ /**
551
+ * 暂停
552
+ */
553
+ pause() {
554
+ this._status = "paused";
555
+ this.timeline.pause();
556
+ return this;
557
+ }
558
+ /**
559
+ * 恢复
560
+ */
561
+ resume() {
562
+ this._status = "running";
563
+ this.timeline.resume();
564
+ return this;
565
+ }
566
+ /**
567
+ * 停止并重置
568
+ */
569
+ restart() {
570
+ this._status = "pending";
571
+ this.timeline.restart();
572
+ return this;
573
+ }
574
+ /**
575
+ * 跳转到指定时间
576
+ */
577
+ seek(time) {
578
+ this.timeline.seek(time);
579
+ return this;
580
+ }
581
+ /**
582
+ * 设置进度
583
+ */
584
+ setProgress(progress) {
585
+ this.timeline.progress(progress);
586
+ return this;
587
+ }
588
+ /**
589
+ * 设置速度
590
+ */
591
+ setSpeed(speed) {
592
+ this.timeline.timeScale(speed);
593
+ return this;
594
+ }
595
+ /**
596
+ * 反向播放
597
+ */
598
+ reverse() {
599
+ this.timeline.reverse();
600
+ return this;
601
+ }
602
+ /**
603
+ * 销毁
604
+ */
605
+ kill() {
606
+ this.timeline.kill();
607
+ }
608
+ /**
609
+ * 等待完成
610
+ */
611
+ async finished() {
612
+ return new Promise((resolve) => {
613
+ this.timeline.eventCallback("onComplete", resolve);
614
+ });
615
+ }
616
+ };
617
+ easingMap = {
618
+ linear: "none",
619
+ easeIn: "power2.in",
620
+ easeOut: "power2.out",
621
+ easeInOut: "power2.inOut",
622
+ easeInQuad: "power1.in",
623
+ easeOutQuad: "power1.out",
624
+ easeInOutQuad: "power1.inOut",
625
+ easeInCubic: "power2.in",
626
+ easeOutCubic: "power2.out",
627
+ easeInOutCubic: "power2.inOut",
628
+ easeInQuart: "power3.in",
629
+ easeOutQuart: "power3.out",
630
+ easeInOutQuart: "power3.inOut",
631
+ easeInQuint: "power4.in",
632
+ easeOutQuint: "power4.out",
633
+ easeInOutQuint: "power4.inOut",
634
+ easeInSine: "sine.in",
635
+ easeOutSine: "sine.out",
636
+ easeInOutSine: "sine.inOut",
637
+ easeInExpo: "expo.in",
638
+ easeOutExpo: "expo.out",
639
+ easeInOutExpo: "expo.inOut",
640
+ easeInCirc: "circ.in",
641
+ easeOutCirc: "circ.out",
642
+ easeInOutCirc: "circ.inOut",
643
+ easeInBack: "back.in",
644
+ easeOutBack: "back.out",
645
+ easeInOutBack: "back.inOut",
646
+ easeInElastic: "elastic.in",
647
+ easeOutElastic: "elastic.out",
648
+ easeInOutElastic: "elastic.inOut",
649
+ easeInBounce: "bounce.in",
650
+ easeOutBounce: "bounce.out",
651
+ easeInOutBounce: "bounce.inOut"
652
+ };
653
+ }
654
+ });
655
+
656
+ // src/core/animate-proxy.ts
657
+ import { gsap as gsap2 } from "gsap";
486
658
  function createAnimateAnimation(proxy) {
487
659
  var _a, _b, _c;
488
660
  const source = proxy.getSource();
@@ -498,7 +670,7 @@ function createAnimateAnimation(proxy) {
498
670
  const sourceElement = scene.getElement(source);
499
671
  const targetElement = scene.getOrCreateElement(target);
500
672
  if (!sourceElement || !targetElement) return;
501
- gsap.set(targetElement, { opacity: 0, visibility: "hidden" });
673
+ gsap2.set(targetElement, { opacity: 0, visibility: "hidden" });
502
674
  const sourceBBox = ((_a2 = sourceElement.getBBox) == null ? void 0 : _a2.call(sourceElement)) || { x: 0, y: 0, width: 0, height: 0 };
503
675
  const targetBBox = ((_b2 = targetElement.getBBox) == null ? void 0 : _b2.call(targetElement)) || { x: 0, y: 0, width: 0, height: 0 };
504
676
  const scaleX = targetBBox.width / (sourceBBox.width || 1);
@@ -509,7 +681,7 @@ function createAnimateAnimation(proxy) {
509
681
  const targetCenterY = targetBBox.y + targetBBox.height / 2;
510
682
  const translateX = targetCenterX - sourceCenterX;
511
683
  const translateY = targetCenterY - sourceCenterY;
512
- gsap.set(sourceElement, {
684
+ gsap2.set(sourceElement, {
513
685
  transformOrigin: `${sourceCenterX}px ${sourceCenterY}px`
514
686
  });
515
687
  const targetStyle = target.shape.style;
@@ -522,7 +694,7 @@ function createAnimateAnimation(proxy) {
522
694
  ease: getGSAPEasing(easing2),
523
695
  onComplete: () => {
524
696
  sourceElement.remove();
525
- gsap.set(targetElement, { opacity: 1, visibility: "visible" });
697
+ gsap2.set(targetElement, { opacity: 1, visibility: "visible" });
526
698
  scene.updateObject(source, target);
527
699
  }
528
700
  };
@@ -908,6 +1080,20 @@ var init_diagram = __esm({
908
1080
  constructor(shape) {
909
1081
  this.shape = shape;
910
1082
  }
1083
+ /**
1084
+ * 设置目标状态(Manim 风格)
1085
+ * 用于 MoveToTarget 动画
1086
+ */
1087
+ setTarget(targetDiagram) {
1088
+ this.target = targetDiagram;
1089
+ return this;
1090
+ }
1091
+ /**
1092
+ * 获取目标状态
1093
+ */
1094
+ getTarget() {
1095
+ return this.target;
1096
+ }
911
1097
  // ========== 样式方法 ==========
912
1098
  /** 设置填充颜色 */
913
1099
  fill(color) {
@@ -2854,44 +3040,97 @@ function braceBetweenPoints(start, end, options) {
2854
3040
  const {
2855
3041
  direction = 1,
2856
3042
  // 1 = 垂直于连线的正方向,-1 = 反方向
2857
- sharpness = 0.3,
2858
- tipExtent = 0.2
3043
+ sharpness = 2,
3044
+ // Manim 默认值
3045
+ tipExtent: _tipExtent = 0.2
3046
+ // 保留向后兼容但不使用
2859
3047
  } = options || {};
2860
3048
  const dx = end[0] - start[0];
2861
3049
  const dy = end[1] - start[1];
2862
3050
  const length2 = Math.sqrt(dx * dx + dy * dy);
2863
- if (length2 < 1) {
3051
+ if (length2 < 1e-3) {
2864
3052
  return path([]);
2865
3053
  }
2866
3054
  const ux = dx / length2;
2867
3055
  const uy = dy / length2;
2868
3056
  const perpX = -uy * direction;
2869
3057
  const perpY = ux * direction;
2870
- const height = length2 * tipExtent;
2871
- const curveDepth = length2 * sharpness * 0.15;
3058
+ const braceHeight = length2 * 0.09;
3059
+ const curlHeight = braceHeight * 0.35;
3060
+ const curlWidth = length2 * 0.02;
3061
+ const defaultMinWidth = 0.90552;
3062
+ const linearRatio = Math.max(0, (sharpness - defaultMinWidth) / 2);
3063
+ const linearLength = linearRatio * length2;
3064
+ const curveWidth = length2 / 2 - linearLength - curlWidth;
2872
3065
  const midX = (start[0] + end[0]) / 2;
2873
3066
  const midY = (start[1] + end[1]) / 2;
2874
- const tipX = midX + perpX * height;
2875
- const tipY = midY + perpY * height;
2876
- const q1X = start[0] + dx * 0.25;
2877
- const q1Y = start[1] + dy * 0.25;
2878
- const q3X = start[0] + dx * 0.75;
2879
- const q3Y = start[1] + dy * 0.75;
2880
- const ctrl1X = start[0] + perpX * curveDepth;
2881
- const ctrl1Y = start[1] + perpY * curveDepth;
2882
- const ctrl2X = q1X + perpX * height * 0.6;
2883
- const ctrl2Y = q1Y + perpY * height * 0.6;
2884
- const ctrl5X = q3X + perpX * height * 0.6;
2885
- const ctrl5Y = q3Y + perpY * height * 0.6;
2886
- const ctrl6X = end[0] + perpX * curveDepth;
2887
- const ctrl6Y = end[1] + perpY * curveDepth;
3067
+ const tipX = midX + perpX * braceHeight;
3068
+ const tipY = midY + perpY * braceHeight;
3069
+ const leftCurlEndX = start[0] + ux * curlWidth - perpX * curlHeight;
3070
+ const leftCurlEndY = start[1] + uy * curlWidth - perpY * curlHeight;
3071
+ const leftLineEndX = leftCurlEndX + ux * linearLength;
3072
+ const leftLineEndY = leftCurlEndY + uy * linearLength;
3073
+ const rightLineStartX = end[0] - ux * (curlWidth + linearLength) - perpX * curlHeight;
3074
+ const rightLineStartY = end[1] - uy * (curlWidth + linearLength) - perpY * curlHeight;
3075
+ const rightCurlStartX = rightLineStartX + ux * linearLength;
3076
+ const rightCurlStartY = rightLineStartY + uy * linearLength;
2888
3077
  const commands = [
2889
3078
  { type: "M", x: start[0], y: start[1] },
2890
- { type: "C", x1: ctrl1X, y1: ctrl1Y, x2: ctrl2X, y2: ctrl2Y, x: tipX - ux * length2 * 0.05, y: tipY - uy * length2 * 0.05 },
2891
- { type: "Q", x1: tipX, y1: tipY, x: tipX + ux * length2 * 0.05, y: tipY + uy * length2 * 0.05 },
2892
- { type: "C", x1: ctrl5X, y1: ctrl5Y, x2: ctrl6X, y2: ctrl6Y, x: end[0], y: end[1] }
3079
+ // 左端卷曲:明显的向外翘小勾
3080
+ // 控制点1向外凸出,控制点2稍微回来
3081
+ {
3082
+ type: "C",
3083
+ x1: start[0] - perpX * curlHeight * 1.2,
3084
+ y1: start[1] - perpY * curlHeight * 1.2,
3085
+ x2: leftCurlEndX - perpX * curlHeight * 0.3,
3086
+ y2: leftCurlEndY - perpY * curlHeight * 0.3,
3087
+ x: leftCurlEndX,
3088
+ y: leftCurlEndY
3089
+ },
3090
+ // 左直线段
3091
+ ...linearLength > 1e-3 ? [{
3092
+ type: "L",
3093
+ x: leftLineEndX,
3094
+ y: leftLineEndY
3095
+ }] : [],
3096
+ // 左曲线到尖端:平滑的弧线
3097
+ {
3098
+ type: "C",
3099
+ x1: leftLineEndX + ux * curveWidth * 0.55,
3100
+ y1: leftLineEndY + uy * curveWidth * 0.55,
3101
+ x2: tipX - ux * curveWidth * 0.25,
3102
+ y2: tipY - uy * curveWidth * 0.25,
3103
+ x: tipX,
3104
+ y: tipY
3105
+ },
3106
+ // 右曲线从尖端:与左侧对称
3107
+ {
3108
+ type: "C",
3109
+ x1: tipX + ux * curveWidth * 0.25,
3110
+ y1: tipY + uy * curveWidth * 0.25,
3111
+ x2: rightLineStartX - ux * curveWidth * 0.55,
3112
+ y2: rightLineStartY - uy * curveWidth * 0.55,
3113
+ x: rightLineStartX,
3114
+ y: rightLineStartY
3115
+ },
3116
+ // 右直线段
3117
+ ...linearLength > 1e-3 ? [{
3118
+ type: "L",
3119
+ x: rightCurlStartX,
3120
+ y: rightCurlStartY
3121
+ }] : [],
3122
+ // 右端卷曲:明显的向外翘小勾
3123
+ {
3124
+ type: "C",
3125
+ x1: rightCurlStartX - perpX * curlHeight * 0.3,
3126
+ y1: rightCurlStartY - perpY * curlHeight * 0.3,
3127
+ x2: end[0] - perpX * curlHeight * 1.2,
3128
+ y2: end[1] - perpY * curlHeight * 1.2,
3129
+ x: end[0],
3130
+ y: end[1]
3131
+ }
2893
3132
  ];
2894
- return path(commands).fill("none").stroke("#374151").strokeWidth(2);
3133
+ return path(commands).fill("none").stroke("#FFFFFF").strokeWidth(2);
2895
3134
  }
2896
3135
  function brace(target, options) {
2897
3136
  var _a;
@@ -2932,22 +3171,27 @@ function brace(target, options) {
2932
3171
  end = [bounds.x - buff, bounds.y + bounds.height];
2933
3172
  }
2934
3173
  }
2935
- const braceDir = 1;
3174
+ let braceDir;
3175
+ if (Math.abs(normDir[1]) > 0.5) {
3176
+ braceDir = normDir[1] > 0 ? 1 : -1;
3177
+ } else {
3178
+ braceDir = normDir[0] > 0 ? -1 : 1;
3179
+ }
2936
3180
  return braceBetweenPoints(start, end, { direction: braceDir, sharpness });
2937
3181
  }
2938
- function getBraceTipPosition(start, end, direction, tipExtent) {
3182
+ function getBraceTipPosition(start, end, direction, _tipExtent) {
2939
3183
  const dx = end[0] - start[0];
2940
3184
  const dy = end[1] - start[1];
2941
3185
  const length2 = Math.sqrt(dx * dx + dy * dy);
2942
- if (length2 < 1) return [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2];
3186
+ if (length2 < 1e-3) return [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2];
2943
3187
  const ux = dx / length2;
2944
3188
  const uy = dy / length2;
2945
3189
  const perpX = -uy * direction;
2946
3190
  const perpY = ux * direction;
2947
3191
  const midX = (start[0] + end[0]) / 2;
2948
3192
  const midY = (start[1] + end[1]) / 2;
2949
- const height = length2 * tipExtent;
2950
- return [midX + perpX * height, midY + perpY * height];
3193
+ const braceHeight = length2 * 0.09;
3194
+ return [midX + perpX * braceHeight, midY + perpY * braceHeight];
2951
3195
  }
2952
3196
  function braceLabel(target, label, options) {
2953
3197
  var _a;
@@ -2959,7 +3203,8 @@ function braceLabel(target, label, options) {
2959
3203
  sharpness = 0.3,
2960
3204
  buff = 0.1,
2961
3205
  // 使用适合数学坐标系的默认值
2962
- labelBuff = 0.15
3206
+ labelBuff = 0.35
3207
+ // 增大默认值,让标签在花括号外侧
2963
3208
  } = options || {};
2964
3209
  const br = brace(target, { direction, sharpness, buff });
2965
3210
  let dir;
@@ -2993,7 +3238,13 @@ function braceLabel(target, label, options) {
2993
3238
  end = [bounds.x - buff, bounds.y + bounds.height];
2994
3239
  }
2995
3240
  }
2996
- const tipPos = getBraceTipPosition(start, end, 1, 0.2);
3241
+ let braceDir;
3242
+ if (Math.abs(normDir[1]) > 0.5) {
3243
+ braceDir = normDir[1] > 0 ? 1 : -1;
3244
+ } else {
3245
+ braceDir = normDir[0] > 0 ? -1 : 1;
3246
+ }
3247
+ const tipPos = getBraceTipPosition(start, end, braceDir, 0.2);
2997
3248
  const labelX = tipPos[0] + normDir[0] * labelBuff;
2998
3249
  const labelY = tipPos[1] + normDir[1] * labelBuff;
2999
3250
  const labelText = text(label, { fontSize }).fill(labelColor).translate(labelX, labelY);
@@ -3118,7 +3369,7 @@ function pathFromString(d) {
3118
3369
  }
3119
3370
  function text(content, options) {
3120
3371
  const {
3121
- fontSize = 16,
3372
+ fontSize = 1,
3122
3373
  fontFamily = "system-ui, sans-serif",
3123
3374
  fontWeight = "normal",
3124
3375
  fontStyle = "normal",
@@ -3146,7 +3397,7 @@ function text(content, options) {
3146
3397
  return new Diagram(shape);
3147
3398
  }
3148
3399
  function tex(latex, options) {
3149
- const { fontSize = 20, color = "#374151" } = options || {};
3400
+ const { fontSize = 1, color = "#374151" } = options || {};
3150
3401
  const html = katex.renderToString(latex, {
3151
3402
  throwOnError: false,
3152
3403
  displayMode: false,
@@ -3207,27 +3458,95 @@ function bulletedList(items, options) {
3207
3458
  }
3208
3459
  function code(source, options) {
3209
3460
  const {
3210
- fontSize = 14,
3461
+ fontSize = 0.25,
3462
+ // 使用适合数学坐标系的默认值
3211
3463
  theme = "dark",
3212
- showLineNumbers = false,
3213
- lineNumberWidth = 30,
3214
- lineHeight = 1.3
3464
+ showLineNumbers = true,
3465
+ // 默认显示行号
3466
+ lineNumberWidth = 0.5,
3467
+ lineHeight = 1.4,
3468
+ showBackground = true,
3469
+ // 默认显示背景
3470
+ showWindowButtons = true,
3471
+ // 默认显示窗口按钮
3472
+ language = "javascript",
3473
+ padding = 0.3
3215
3474
  } = options || {};
3216
3475
  const fontFamily = 'Consolas, Monaco, "Courier New", monospace';
3217
3476
  const lines = source.split("\n");
3218
3477
  const lineSpacing = fontSize * lineHeight;
3219
- const textColor = theme === "dark" ? "#E5E7EB" : "#374151";
3220
- const lineNumColor = theme === "dark" ? "#6B7280" : "#9CA3AF";
3478
+ const bgColor = theme === "dark" ? "#1E1E2E" : "#F8F8F8";
3479
+ const textColor = theme === "dark" ? "#CDD6F4" : "#374151";
3480
+ const lineNumColor = theme === "dark" ? "#6C7086" : "#9CA3AF";
3481
+ const keywordColor = theme === "dark" ? "#CBA6F7" : "#7C3AED";
3482
+ const stringColor = theme === "dark" ? "#A6E3A1" : "#059669";
3483
+ const numberColor = theme === "dark" ? "#FAB387" : "#D97706";
3484
+ const commentColor = theme === "dark" ? "#6C7086" : "#9CA3AF";
3485
+ const keywords = ["const", "let", "var", "function", "return", "if", "else", "for", "while", "class", "import", "export", "from", "async", "await", "new", "this", "true", "false", "null", "undefined"];
3486
+ const highlightLine = (lineContent) => {
3487
+ const tokens = [];
3488
+ let x = 0;
3489
+ const regex = /(\s+)|("[^"]*"|'[^']*')|(\d+\.?\d*)|(\b\w+\b)|(\/\/.*$)|([^\s\w"']+)/g;
3490
+ let match;
3491
+ while ((match = regex.exec(lineContent)) !== null) {
3492
+ const token = match[0];
3493
+ let color = textColor;
3494
+ if (match[1]) {
3495
+ x += token.length * fontSize * 0.6;
3496
+ continue;
3497
+ } else if (match[2]) {
3498
+ color = stringColor;
3499
+ } else if (match[3]) {
3500
+ color = numberColor;
3501
+ } else if (match[4] && keywords.includes(token)) {
3502
+ color = keywordColor;
3503
+ } else if (match[5]) {
3504
+ color = commentColor;
3505
+ }
3506
+ const tokenText = text(token, { fontSize, fontFamily, anchor: "start" }).fill(color).translate(x, 0);
3507
+ tokens.push(tokenText);
3508
+ x += token.length * fontSize * 0.6;
3509
+ }
3510
+ return tokens;
3511
+ };
3221
3512
  const elements = [];
3513
+ const maxLineLength = Math.max(...lines.map((l) => l.length), 1);
3514
+ const contentWidth = (showLineNumbers ? lineNumberWidth : 0) + maxLineLength * fontSize * 0.6 + padding;
3515
+ const contentHeight = lines.length * lineSpacing + padding * 2;
3516
+ const headerHeight = showWindowButtons ? 0.4 : 0;
3517
+ const totalHeight = contentHeight + headerHeight;
3518
+ if (showBackground) {
3519
+ const cornerRadius = 0.15;
3520
+ const bg = rect(contentWidth + padding * 2, totalHeight, { rx: cornerRadius, ry: cornerRadius }).fill(bgColor).translate(contentWidth / 2, -totalHeight / 2 + headerHeight + padding);
3521
+ elements.push(bg);
3522
+ }
3523
+ if (showWindowButtons && showBackground) {
3524
+ const buttonY = headerHeight / 2 + padding * 0.5;
3525
+ const buttonRadius = 0.08;
3526
+ const buttonSpacing = 0.25;
3527
+ const buttonStartX = padding + 0.2;
3528
+ const redBtn = circle(buttonRadius).fill("#FF5F56").translate(buttonStartX, buttonY);
3529
+ const yellowBtn = circle(buttonRadius).fill("#FFBD2E").translate(buttonStartX + buttonSpacing, buttonY);
3530
+ const greenBtn = circle(buttonRadius).fill("#27C93F").translate(buttonStartX + buttonSpacing * 2, buttonY);
3531
+ elements.push(redBtn, yellowBtn, greenBtn);
3532
+ }
3533
+ const codeStartY = showWindowButtons ? -headerHeight : 0;
3222
3534
  lines.forEach((lineContent, i) => {
3223
- const y = -i * lineSpacing;
3535
+ const y = codeStartY - i * lineSpacing - padding;
3224
3536
  if (showLineNumbers) {
3225
- const lineNum = text(String(i + 1), { fontSize, fontFamily, anchor: "end" }).fill(lineNumColor).translate(lineNumberWidth - 5, y);
3537
+ const lineNum = text(String(i + 1), { fontSize, fontFamily, anchor: "end" }).fill(lineNumColor).translate(lineNumberWidth + padding - 0.05, y);
3226
3538
  elements.push(lineNum);
3227
3539
  }
3228
- const xOffset = showLineNumbers ? lineNumberWidth + 10 : 0;
3229
- const codeLine = text(lineContent || " ", { fontSize, fontFamily, anchor: "start" }).fill(textColor).translate(xOffset, y);
3230
- elements.push(codeLine);
3540
+ const xOffset = (showLineNumbers ? lineNumberWidth + 0.15 : 0) + padding;
3541
+ if (language && lineContent.trim()) {
3542
+ const highlightedTokens = highlightLine(lineContent);
3543
+ highlightedTokens.forEach((token) => {
3544
+ elements.push(token.translate(xOffset, y));
3545
+ });
3546
+ } else {
3547
+ const codeLine = text(lineContent || " ", { fontSize, fontFamily, anchor: "start" }).fill(textColor).translate(xOffset, y);
3548
+ elements.push(codeLine);
3549
+ }
3231
3550
  });
3232
3551
  if (elements.length === 0) {
3233
3552
  return group();
@@ -3236,11 +3555,104 @@ function code(source, options) {
3236
3555
  }
3237
3556
  function markupText(content, options) {
3238
3557
  const {
3239
- fontSize = 16,
3240
- fontFamily = "system-ui, sans-serif"
3558
+ fontSize = 0.4,
3559
+ // 使用适合数学坐标系的默认值
3560
+ fontFamily = "system-ui, sans-serif",
3561
+ color = "#FFFFFF"
3241
3562
  } = options || {};
3242
- const plainText = content.replace(/<b>|<\/b>/g, "").replace(/<i>|<\/i>/g, "").replace(/<color=[^>]*>|<\/color>/g, "").replace(/<sub>|<\/sub>/g, "").replace(/<sup>|<\/sup>/g, "");
3243
- return text(plainText, { fontSize, fontFamily });
3563
+ const parseMarkup = (input) => {
3564
+ const segments2 = [];
3565
+ let currentText = "";
3566
+ let bold = false;
3567
+ let italic = false;
3568
+ let currentColor;
3569
+ let i = 0;
3570
+ while (i < input.length) {
3571
+ if (input.slice(i).startsWith("<b>")) {
3572
+ if (currentText) {
3573
+ segments2.push({ text: currentText, bold, italic, color: currentColor });
3574
+ currentText = "";
3575
+ }
3576
+ bold = true;
3577
+ i += 3;
3578
+ continue;
3579
+ }
3580
+ if (input.slice(i).startsWith("</b>")) {
3581
+ if (currentText) {
3582
+ segments2.push({ text: currentText, bold, italic, color: currentColor });
3583
+ currentText = "";
3584
+ }
3585
+ bold = false;
3586
+ i += 4;
3587
+ continue;
3588
+ }
3589
+ if (input.slice(i).startsWith("<i>")) {
3590
+ if (currentText) {
3591
+ segments2.push({ text: currentText, bold, italic, color: currentColor });
3592
+ currentText = "";
3593
+ }
3594
+ italic = true;
3595
+ i += 3;
3596
+ continue;
3597
+ }
3598
+ if (input.slice(i).startsWith("</i>")) {
3599
+ if (currentText) {
3600
+ segments2.push({ text: currentText, bold, italic, color: currentColor });
3601
+ currentText = "";
3602
+ }
3603
+ italic = false;
3604
+ i += 4;
3605
+ continue;
3606
+ }
3607
+ const colorMatch = input.slice(i).match(/^<color=([^>]+)>/);
3608
+ if (colorMatch) {
3609
+ if (currentText) {
3610
+ segments2.push({ text: currentText, bold, italic, color: currentColor });
3611
+ currentText = "";
3612
+ }
3613
+ currentColor = colorMatch[1];
3614
+ i += colorMatch[0].length;
3615
+ continue;
3616
+ }
3617
+ if (input.slice(i).startsWith("</color>")) {
3618
+ if (currentText) {
3619
+ segments2.push({ text: currentText, bold, italic, color: currentColor });
3620
+ currentText = "";
3621
+ }
3622
+ currentColor = void 0;
3623
+ i += 8;
3624
+ continue;
3625
+ }
3626
+ currentText += input[i];
3627
+ i++;
3628
+ }
3629
+ if (currentText) {
3630
+ segments2.push({ text: currentText, bold, italic, color: currentColor });
3631
+ }
3632
+ return segments2;
3633
+ };
3634
+ const segments = parseMarkup(content);
3635
+ const elements = [];
3636
+ let x = 0;
3637
+ segments.forEach((segment) => {
3638
+ if (!segment.text) return;
3639
+ const fontWeight = segment.bold ? "bold" : "normal";
3640
+ const fontStyle = segment.italic ? "italic" : "normal";
3641
+ const textColor = segment.color || color;
3642
+ const segmentText = text(segment.text, {
3643
+ fontSize,
3644
+ fontFamily,
3645
+ fontWeight,
3646
+ fontStyle,
3647
+ anchor: "start"
3648
+ }).fill(textColor).translate(x, 0);
3649
+ elements.push(segmentText);
3650
+ x += segment.text.length * fontSize * 0.6;
3651
+ });
3652
+ if (elements.length === 0) {
3653
+ return text("", { fontSize, fontFamily });
3654
+ }
3655
+ return elements[0].combine(...elements.slice(1));
3244
3656
  }
3245
3657
  function crossMark(size, options) {
3246
3658
  const { strokeWidth = 2, style = "x" } = options || {};
@@ -4959,7 +5371,18 @@ var SimpleMovingCameraScene = class extends MovingCameraScene {
4959
5371
 
4960
5372
  // src/animate/animations/create.ts
4961
5373
  init_timeline();
4962
- import { gsap as gsap2 } from "gsap";
5374
+ import { gsap as gsap3 } from "gsap";
5375
+
5376
+ // src/animate/animations/utils.ts
5377
+ function querySelectorAllIncludingSelf(element, selector) {
5378
+ const results = Array.from(element.querySelectorAll(selector));
5379
+ if (element.matches(selector)) {
5380
+ results.unshift(element);
5381
+ }
5382
+ return results;
5383
+ }
5384
+
5385
+ // src/animate/animations/create.ts
4963
5386
  function Create(target, options = {}) {
4964
5387
  const { duration = 1, easing: easing2 = "easeInOut", delay = 0 } = options;
4965
5388
  return {
@@ -4972,7 +5395,7 @@ function Create(target, options = {}) {
4972
5395
  paths.forEach((path2) => {
4973
5396
  if (path2 instanceof SVGGeometryElement) {
4974
5397
  const length2 = path2.getTotalLength();
4975
- gsap2.set(path2, {
5398
+ gsap3.set(path2, {
4976
5399
  strokeDasharray: length2,
4977
5400
  strokeDashoffset: length2,
4978
5401
  fillOpacity: 0
@@ -4995,7 +5418,7 @@ function Create(target, options = {}) {
4995
5418
  });
4996
5419
  const texts = querySelectorAllIncludingSelf(element, "text");
4997
5420
  texts.forEach((text2) => {
4998
- gsap2.set(text2, { opacity: 0 });
5421
+ gsap3.set(text2, { opacity: 0 });
4999
5422
  timeline.add(text2, {
5000
5423
  opacity: 1,
5001
5424
  duration: duration * 0.5,
@@ -5022,7 +5445,7 @@ function Write(target, options = {}) {
5022
5445
  chars.forEach((char, i) => {
5023
5446
  const tspan = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
5024
5447
  tspan.textContent = char;
5025
- gsap2.set(tspan, { opacity: 0 });
5448
+ gsap3.set(tspan, { opacity: 0 });
5026
5449
  text2.appendChild(tspan);
5027
5450
  const charDelay = i / chars.length * duration;
5028
5451
  timeline.add(tspan, {
@@ -5052,7 +5475,7 @@ function DrawBorderThenFill(target, options = {}) {
5052
5475
  const length2 = path2.getTotalLength();
5053
5476
  const originalFill = path2.getAttribute("fill") || "none";
5054
5477
  const originalStroke = path2.getAttribute("stroke") || "#374151";
5055
- gsap2.set(path2, {
5478
+ gsap3.set(path2, {
5056
5479
  strokeDasharray: length2,
5057
5480
  strokeDashoffset: length2,
5058
5481
  fill: "none",
@@ -5091,7 +5514,7 @@ function GrowFromCenter(target, options = {}) {
5091
5514
  const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
5092
5515
  const cx = bbox.x + bbox.width / 2;
5093
5516
  const cy = bbox.y + bbox.height / 2;
5094
- gsap2.set(element, {
5517
+ gsap3.set(element, {
5095
5518
  transformOrigin: `${cx}px ${cy}px`,
5096
5519
  scale: 0,
5097
5520
  opacity: 0
@@ -5114,7 +5537,7 @@ function GrowFromPoint(target, point, options = {}) {
5114
5537
  execute(scene, timeline, startTime) {
5115
5538
  const element = scene.getOrCreateElement(target);
5116
5539
  if (!element) return;
5117
- gsap2.set(element, {
5540
+ gsap3.set(element, {
5118
5541
  transformOrigin: `${point[0]}px ${point[1]}px`,
5119
5542
  scale: 0,
5120
5543
  opacity: 0
@@ -5159,7 +5582,7 @@ function GrowFromEdge(target, edge = "LEFT", options = {}) {
5159
5582
  scaleFrom = { scaleY: 0 };
5160
5583
  break;
5161
5584
  }
5162
- gsap2.set(element, __spreadProps(__spreadValues({
5585
+ gsap3.set(element, __spreadProps(__spreadValues({
5163
5586
  transformOrigin: origin
5164
5587
  }, scaleFrom), {
5165
5588
  opacity: 0
@@ -5187,7 +5610,7 @@ function SpinInFromNothing(target, options = {}) {
5187
5610
  const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
5188
5611
  const cx = bbox.x + bbox.width / 2;
5189
5612
  const cy = bbox.y + bbox.height / 2;
5190
- gsap2.set(element, {
5613
+ gsap3.set(element, {
5191
5614
  transformOrigin: `${cx}px ${cy}px`,
5192
5615
  scale: 0,
5193
5616
  rotation: -360,
@@ -5216,7 +5639,7 @@ function Uncreate(target, options = {}) {
5216
5639
  paths.forEach((path2) => {
5217
5640
  if (path2 instanceof SVGGeometryElement) {
5218
5641
  const length2 = path2.getTotalLength();
5219
- gsap2.set(path2, {
5642
+ gsap3.set(path2, {
5220
5643
  strokeDasharray: length2,
5221
5644
  strokeDashoffset: 0
5222
5645
  });
@@ -5297,7 +5720,7 @@ function ShrinkToCenter(target, options = {}) {
5297
5720
  const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
5298
5721
  const cx = bbox.x + bbox.width / 2;
5299
5722
  const cy = bbox.y + bbox.height / 2;
5300
- gsap2.set(element, {
5723
+ gsap3.set(element, {
5301
5724
  transformOrigin: `${cx}px ${cy}px`
5302
5725
  });
5303
5726
  timeline.add(element, {
@@ -5317,7 +5740,7 @@ function ShrinkToCenter(target, options = {}) {
5317
5740
  // src/animate/animations/fade.ts
5318
5741
  init_math();
5319
5742
  init_timeline();
5320
- import { gsap as gsap3 } from "gsap";
5743
+ import { gsap as gsap4 } from "gsap";
5321
5744
  function directionToVector(direction) {
5322
5745
  if (!direction) return void 0;
5323
5746
  if (Array.isArray(direction)) return direction;
@@ -5346,7 +5769,7 @@ function FadeIn(target, options = {}) {
5346
5769
  initialState.x = -dir[0] * shift;
5347
5770
  initialState.y = -dir[1] * shift;
5348
5771
  }
5349
- gsap3.set(element, initialState);
5772
+ gsap4.set(element, initialState);
5350
5773
  const targetState = {
5351
5774
  opacity: 1,
5352
5775
  duration,
@@ -5405,41 +5828,423 @@ function FadeInFromLeft(target, options = {}) {
5405
5828
  function FadeInFromRight(target, options = {}) {
5406
5829
  return FadeIn(target, __spreadProps(__spreadValues({}, options), { direction: "RIGHT" }));
5407
5830
  }
5408
- function FadeTransform(source, target, options = {}) {
5409
- const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0 } = options;
5831
+ function FadeTransform(source, target, options = {}) {
5832
+ const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0 } = options;
5833
+ return {
5834
+ duration,
5835
+ target: source,
5836
+ execute(scene, timeline, startTime) {
5837
+ const sourceElement = scene.getElement(source);
5838
+ const targetElement = scene.getOrCreateElement(target);
5839
+ if (!sourceElement || !targetElement) return;
5840
+ gsap4.set(targetElement, { opacity: 0 });
5841
+ timeline.add(sourceElement, {
5842
+ opacity: 0,
5843
+ duration,
5844
+ ease: getGSAPEasing(easing2),
5845
+ delay,
5846
+ onComplete: () => {
5847
+ sourceElement.remove();
5848
+ }
5849
+ }, startTime);
5850
+ timeline.add(targetElement, {
5851
+ opacity: 1,
5852
+ duration,
5853
+ ease: getGSAPEasing(easing2),
5854
+ delay
5855
+ }, startTime);
5856
+ }
5857
+ };
5858
+ }
5859
+
5860
+ // src/animate/animations/transform.ts
5861
+ init_timeline();
5862
+ import { gsap as gsap5 } from "gsap";
5863
+ function Transform(source, target, options = {}) {
5864
+ const { duration = 1, easing: easing2 = "easeInOut", delay = 0 } = options;
5865
+ return {
5866
+ duration,
5867
+ target: source,
5868
+ execute(scene, timeline, startTime) {
5869
+ var _a, _b;
5870
+ const sourceElement = scene.getElement(source);
5871
+ const targetElement = scene.getOrCreateElement(target);
5872
+ if (!sourceElement || !targetElement) return;
5873
+ gsap5.set(targetElement, { opacity: 0 });
5874
+ const sourceBBox = ((_a = sourceElement.getBBox) == null ? void 0 : _a.call(sourceElement)) || { x: 0, y: 0, width: 0, height: 0 };
5875
+ const targetBBox = ((_b = targetElement.getBBox) == null ? void 0 : _b.call(targetElement)) || { x: 0, y: 0, width: 0, height: 0 };
5876
+ const scaleX = targetBBox.width / (sourceBBox.width || 1);
5877
+ const scaleY = targetBBox.height / (sourceBBox.height || 1);
5878
+ const translateX = targetBBox.x + targetBBox.width / 2 - (sourceBBox.x + sourceBBox.width / 2);
5879
+ const translateY = targetBBox.y + targetBBox.height / 2 - (sourceBBox.y + sourceBBox.height / 2);
5880
+ const originX = sourceBBox.x + sourceBBox.width / 2;
5881
+ const originY = sourceBBox.y + sourceBBox.height / 2;
5882
+ gsap5.set(sourceElement, {
5883
+ transformOrigin: `${originX}px ${originY}px`
5884
+ });
5885
+ timeline.add(sourceElement, {
5886
+ scaleX,
5887
+ scaleY,
5888
+ x: translateX,
5889
+ y: translateY,
5890
+ duration,
5891
+ ease: getGSAPEasing(easing2),
5892
+ delay,
5893
+ onComplete: () => {
5894
+ sourceElement.remove();
5895
+ gsap5.set(targetElement, { opacity: 1 });
5896
+ }
5897
+ }, startTime);
5898
+ }
5899
+ };
5900
+ }
5901
+ function ReplacementTransform(source, target, options = {}) {
5902
+ const { duration = 1, easing: easing2 = "easeInOut", delay = 0, replace = true } = options;
5903
+ return {
5904
+ duration,
5905
+ target: source,
5906
+ execute(scene, timeline, startTime) {
5907
+ var _a, _b;
5908
+ const sourceElement = scene.getElement(source);
5909
+ const targetElement = scene.getOrCreateElement(target);
5910
+ if (!sourceElement || !targetElement) return;
5911
+ gsap5.set(targetElement, { opacity: 0, visibility: "hidden" });
5912
+ const sourceBBox = ((_a = sourceElement.getBBox) == null ? void 0 : _a.call(sourceElement)) || { x: 0, y: 0, width: 0, height: 0 };
5913
+ const targetBBox = ((_b = targetElement.getBBox) == null ? void 0 : _b.call(targetElement)) || { x: 0, y: 0, width: 0, height: 0 };
5914
+ const scaleX = targetBBox.width / (sourceBBox.width || 1);
5915
+ const scaleY = targetBBox.height / (sourceBBox.height || 1);
5916
+ const sourceCenterX = sourceBBox.x + sourceBBox.width / 2;
5917
+ const sourceCenterY = sourceBBox.y + sourceBBox.height / 2;
5918
+ const targetCenterX = targetBBox.x + targetBBox.width / 2;
5919
+ const targetCenterY = targetBBox.y + targetBBox.height / 2;
5920
+ timeline.add(sourceElement, {
5921
+ transformOrigin: `${sourceCenterX}px ${sourceCenterY}px`,
5922
+ scaleX,
5923
+ scaleY,
5924
+ x: targetCenterX - sourceCenterX,
5925
+ y: targetCenterY - sourceCenterY,
5926
+ opacity: 0,
5927
+ duration,
5928
+ ease: getGSAPEasing(easing2),
5929
+ delay,
5930
+ onComplete: () => {
5931
+ if (replace) {
5932
+ sourceElement.remove();
5933
+ }
5934
+ }
5935
+ }, startTime);
5936
+ timeline.add(targetElement, {
5937
+ visibility: "visible",
5938
+ opacity: 1,
5939
+ duration: duration * 0.5,
5940
+ ease: "power2.out",
5941
+ delay: delay + duration * 0.5
5942
+ }, startTime);
5943
+ }
5944
+ };
5945
+ }
5946
+ function MoveToTarget(source, options = {}) {
5947
+ const { duration = 1, easing: easing2 = "easeInOut", delay = 0 } = options;
5948
+ const targetDiagram = source.getTarget();
5949
+ return {
5950
+ duration,
5951
+ target: source,
5952
+ execute(scene, timeline, startTime) {
5953
+ var _a, _b, _c, _d, _e, _f;
5954
+ const element = scene.getOrCreateElement(source);
5955
+ if (!element || !targetDiagram) return;
5956
+ const sourceBounds = source.bounds();
5957
+ const targetBounds = targetDiagram.bounds();
5958
+ const sourceCenter = [
5959
+ sourceBounds.x + sourceBounds.width / 2,
5960
+ sourceBounds.y + sourceBounds.height / 2
5961
+ ];
5962
+ const targetCenter = [
5963
+ targetBounds.x + targetBounds.width / 2,
5964
+ targetBounds.y + targetBounds.height / 2
5965
+ ];
5966
+ const translateX = ((_a = targetCenter[0]) != null ? _a : 0) - ((_b = sourceCenter[0]) != null ? _b : 0);
5967
+ const translateY = ((_c = targetCenter[1]) != null ? _c : 0) - ((_d = sourceCenter[1]) != null ? _d : 0);
5968
+ const scaleX = targetBounds.width / (sourceBounds.width || 1);
5969
+ const scaleY = targetBounds.height / (sourceBounds.height || 1);
5970
+ gsap5.set(element, {
5971
+ transformOrigin: `${(_e = sourceCenter[0]) != null ? _e : 0}px ${(_f = sourceCenter[1]) != null ? _f : 0}px`
5972
+ });
5973
+ timeline.add(element, {
5974
+ x: translateX,
5975
+ y: -translateY,
5976
+ // SVG Y 轴翻转
5977
+ scaleX: isFinite(scaleX) ? scaleX : 1,
5978
+ scaleY: isFinite(scaleY) ? scaleY : 1,
5979
+ duration,
5980
+ ease: getGSAPEasing(easing2),
5981
+ delay
5982
+ }, startTime);
5983
+ }
5984
+ };
5985
+ }
5986
+ function Morphing(source, target, options = {}) {
5987
+ const { duration = 1, easing: easing2 = "easeInOut", delay = 0 } = options;
5988
+ return {
5989
+ duration,
5990
+ target: source,
5991
+ execute(scene, timeline, startTime) {
5992
+ var _a;
5993
+ const sourceElement = scene.getElement(source);
5994
+ const targetElement = scene.getOrCreateElement(target);
5995
+ if (!sourceElement || !targetElement) return;
5996
+ const sourcePath = sourceElement.querySelector("path") || sourceElement;
5997
+ const targetPath = targetElement.querySelector("path") || targetElement;
5998
+ gsap5.set(targetElement, { opacity: 0 });
5999
+ if ((_a = gsap5.plugins) == null ? void 0 : _a.morphSVG) {
6000
+ const targetD = targetPath.getAttribute("d");
6001
+ if (targetD) {
6002
+ timeline.add(sourcePath, {
6003
+ morphSVG: targetD,
6004
+ duration,
6005
+ ease: getGSAPEasing(easing2),
6006
+ delay,
6007
+ onComplete: () => {
6008
+ sourceElement.remove();
6009
+ gsap5.set(targetElement, { opacity: 1 });
6010
+ }
6011
+ }, startTime);
6012
+ }
6013
+ } else {
6014
+ Transform(source, target, options).execute(scene, timeline, startTime);
6015
+ }
6016
+ }
6017
+ };
6018
+ }
6019
+ function TransformMatchingShapes(source, target, options = {}) {
6020
+ const { duration = 1, easing: easing2 = "easeInOut", delay = 0 } = options;
6021
+ return {
6022
+ duration,
6023
+ target: source,
6024
+ execute(scene, timeline, startTime) {
6025
+ var _a, _b;
6026
+ const sourceElement = scene.getElement(source);
6027
+ const targetElement = scene.getOrCreateElement(target);
6028
+ if (!sourceElement || !targetElement) return;
6029
+ const sourceChildren = Array.from(sourceElement.children);
6030
+ const targetChildren = Array.from(targetElement.children);
6031
+ gsap5.set(targetElement, { opacity: 0 });
6032
+ const pairs = Math.min(sourceChildren.length, targetChildren.length);
6033
+ for (let i = 0; i < pairs; i++) {
6034
+ const sourceChild = sourceChildren[i];
6035
+ const targetChild = targetChildren[i];
6036
+ const sourceBBox = ((_a = sourceChild.getBBox) == null ? void 0 : _a.call(sourceChild)) || { x: 0, y: 0, width: 0, height: 0 };
6037
+ const targetBBox = ((_b = targetChild.getBBox) == null ? void 0 : _b.call(targetChild)) || { x: 0, y: 0, width: 0, height: 0 };
6038
+ const scaleX = targetBBox.width / (sourceBBox.width || 1);
6039
+ const scaleY = targetBBox.height / (sourceBBox.height || 1);
6040
+ const translateX = targetBBox.x - sourceBBox.x;
6041
+ const translateY = targetBBox.y - sourceBBox.y;
6042
+ timeline.add(sourceChild, {
6043
+ scaleX,
6044
+ scaleY,
6045
+ x: translateX,
6046
+ y: translateY,
6047
+ duration,
6048
+ ease: getGSAPEasing(easing2),
6049
+ delay
6050
+ }, startTime);
6051
+ }
6052
+ for (let i = pairs; i < sourceChildren.length; i++) {
6053
+ const child = sourceChildren[i];
6054
+ if (child) {
6055
+ timeline.add(child, {
6056
+ opacity: 0,
6057
+ duration: duration * 0.5,
6058
+ ease: "power2.in"
6059
+ }, startTime);
6060
+ }
6061
+ }
6062
+ timeline.call(() => {
6063
+ sourceElement.remove();
6064
+ gsap5.set(targetElement, { opacity: 1 });
6065
+ }, startTime + duration);
6066
+ }
6067
+ };
6068
+ }
6069
+ function TransformMatchingTex(source, target, options = {}) {
6070
+ const { duration = 1, easing: easing2 = "easeInOut", delay = 0 } = options;
6071
+ return {
6072
+ duration,
6073
+ target: source,
6074
+ execute(scene, timeline, startTime) {
6075
+ var _a, _b;
6076
+ const sourceElement = scene.getElement(source);
6077
+ const targetElement = scene.getOrCreateElement(target);
6078
+ if (!sourceElement || !targetElement) return;
6079
+ gsap5.set(targetElement, { opacity: 0 });
6080
+ const sourceTexParts = querySelectorAllIncludingSelf(sourceElement, "path, use, text");
6081
+ const targetTexParts = querySelectorAllIncludingSelf(targetElement, "path, use, text");
6082
+ const pairs = Math.min(sourceTexParts.length, targetTexParts.length);
6083
+ for (let i = 0; i < pairs; i++) {
6084
+ const sourcePart = sourceTexParts[i];
6085
+ const targetPart = targetTexParts[i];
6086
+ const sourceBBox = ((_a = sourcePart.getBBox) == null ? void 0 : _a.call(sourcePart)) || { x: 0, y: 0, width: 0, height: 0 };
6087
+ const targetBBox = ((_b = targetPart.getBBox) == null ? void 0 : _b.call(targetPart)) || { x: 0, y: 0, width: 0, height: 0 };
6088
+ const scaleX = targetBBox.width / (sourceBBox.width || 1);
6089
+ const scaleY = targetBBox.height / (sourceBBox.height || 1);
6090
+ const translateX = targetBBox.x + targetBBox.width / 2 - (sourceBBox.x + sourceBBox.width / 2);
6091
+ const translateY = targetBBox.y + targetBBox.height / 2 - (sourceBBox.y + sourceBBox.height / 2);
6092
+ timeline.add(sourcePart, {
6093
+ scaleX: isFinite(scaleX) ? scaleX : 1,
6094
+ scaleY: isFinite(scaleY) ? scaleY : 1,
6095
+ x: translateX,
6096
+ y: translateY,
6097
+ duration,
6098
+ ease: getGSAPEasing(easing2),
6099
+ delay
6100
+ }, startTime);
6101
+ }
6102
+ for (let i = pairs; i < sourceTexParts.length; i++) {
6103
+ const part = sourceTexParts[i];
6104
+ if (part) {
6105
+ timeline.add(part, {
6106
+ opacity: 0,
6107
+ duration: duration * 0.5,
6108
+ ease: "power2.in"
6109
+ }, startTime);
6110
+ }
6111
+ }
6112
+ timeline.call(() => {
6113
+ sourceElement.remove();
6114
+ gsap5.set(targetElement, { opacity: 1 });
6115
+ }, startTime + duration);
6116
+ }
6117
+ };
6118
+ }
6119
+ function ClockwiseTransform(source, target, options = {}) {
6120
+ const { duration = 1, easing: easing2 = "easeInOut", delay = 0 } = options;
6121
+ return {
6122
+ duration,
6123
+ target: source,
6124
+ execute(scene, timeline, startTime) {
6125
+ var _a, _b;
6126
+ const sourceElement = scene.getElement(source);
6127
+ const targetElement = scene.getOrCreateElement(target);
6128
+ if (!sourceElement || !targetElement) return;
6129
+ gsap5.set(targetElement, { opacity: 0 });
6130
+ const sourceBBox = ((_a = sourceElement.getBBox) == null ? void 0 : _a.call(sourceElement)) || { x: 0, y: 0, width: 0, height: 0 };
6131
+ const targetBBox = ((_b = targetElement.getBBox) == null ? void 0 : _b.call(targetElement)) || { x: 0, y: 0, width: 0, height: 0 };
6132
+ const sourceCenterX = sourceBBox.x + sourceBBox.width / 2;
6133
+ const sourceCenterY = sourceBBox.y + sourceBBox.height / 2;
6134
+ const targetCenterX = targetBBox.x + targetBBox.width / 2;
6135
+ const targetCenterY = targetBBox.y + targetBBox.height / 2;
6136
+ const scaleX = targetBBox.width / (sourceBBox.width || 1);
6137
+ const scaleY = targetBBox.height / (sourceBBox.height || 1);
6138
+ gsap5.set(sourceElement, {
6139
+ transformOrigin: `${sourceCenterX}px ${sourceCenterY}px`
6140
+ });
6141
+ timeline.add(sourceElement, {
6142
+ rotation: 180,
6143
+ scaleX: isFinite(scaleX) ? scaleX : 1,
6144
+ scaleY: isFinite(scaleY) ? scaleY : 1,
6145
+ x: targetCenterX - sourceCenterX,
6146
+ y: targetCenterY - sourceCenterY,
6147
+ opacity: 0,
6148
+ duration,
6149
+ ease: getGSAPEasing(easing2),
6150
+ delay,
6151
+ onComplete: () => {
6152
+ sourceElement.remove();
6153
+ gsap5.set(targetElement, { opacity: 1 });
6154
+ }
6155
+ }, startTime);
6156
+ }
6157
+ };
6158
+ }
6159
+ function CounterclockwiseTransform(source, target, options = {}) {
6160
+ const { duration = 1, easing: easing2 = "easeInOut", delay = 0 } = options;
6161
+ return {
6162
+ duration,
6163
+ target: source,
6164
+ execute(scene, timeline, startTime) {
6165
+ var _a, _b;
6166
+ const sourceElement = scene.getElement(source);
6167
+ const targetElement = scene.getOrCreateElement(target);
6168
+ if (!sourceElement || !targetElement) return;
6169
+ gsap5.set(targetElement, { opacity: 0 });
6170
+ const sourceBBox = ((_a = sourceElement.getBBox) == null ? void 0 : _a.call(sourceElement)) || { x: 0, y: 0, width: 0, height: 0 };
6171
+ const targetBBox = ((_b = targetElement.getBBox) == null ? void 0 : _b.call(targetElement)) || { x: 0, y: 0, width: 0, height: 0 };
6172
+ const sourceCenterX = sourceBBox.x + sourceBBox.width / 2;
6173
+ const sourceCenterY = sourceBBox.y + sourceBBox.height / 2;
6174
+ const targetCenterX = targetBBox.x + targetBBox.width / 2;
6175
+ const targetCenterY = targetBBox.y + targetBBox.height / 2;
6176
+ const scaleX = targetBBox.width / (sourceBBox.width || 1);
6177
+ const scaleY = targetBBox.height / (sourceBBox.height || 1);
6178
+ gsap5.set(sourceElement, {
6179
+ transformOrigin: `${sourceCenterX}px ${sourceCenterY}px`
6180
+ });
6181
+ timeline.add(sourceElement, {
6182
+ rotation: -180,
6183
+ scaleX: isFinite(scaleX) ? scaleX : 1,
6184
+ scaleY: isFinite(scaleY) ? scaleY : 1,
6185
+ x: targetCenterX - sourceCenterX,
6186
+ y: targetCenterY - sourceCenterY,
6187
+ opacity: 0,
6188
+ duration,
6189
+ ease: getGSAPEasing(easing2),
6190
+ delay,
6191
+ onComplete: () => {
6192
+ sourceElement.remove();
6193
+ gsap5.set(targetElement, { opacity: 1 });
6194
+ }
6195
+ }, startTime);
6196
+ }
6197
+ };
6198
+ }
6199
+ function TransformFromCopy(source, target, options = {}) {
6200
+ const { duration = 1, easing: easing2 = "easeInOut", delay = 0 } = options;
5410
6201
  return {
5411
6202
  duration,
5412
6203
  target: source,
5413
6204
  execute(scene, timeline, startTime) {
6205
+ var _a, _b, _c;
5414
6206
  const sourceElement = scene.getElement(source);
5415
6207
  const targetElement = scene.getOrCreateElement(target);
5416
6208
  if (!sourceElement || !targetElement) return;
5417
- gsap3.set(targetElement, { opacity: 0 });
5418
- timeline.add(sourceElement, {
6209
+ gsap5.set(targetElement, { opacity: 0 });
6210
+ const copyElement = sourceElement.cloneNode(true);
6211
+ copyElement.setAttribute("id", `${sourceElement.id}-copy-${Date.now()}`);
6212
+ (_a = sourceElement.parentNode) == null ? void 0 : _a.appendChild(copyElement);
6213
+ const sourceBBox = ((_b = sourceElement.getBBox) == null ? void 0 : _b.call(sourceElement)) || { x: 0, y: 0, width: 0, height: 0 };
6214
+ const targetBBox = ((_c = targetElement.getBBox) == null ? void 0 : _c.call(targetElement)) || { x: 0, y: 0, width: 0, height: 0 };
6215
+ const sourceCenterX = sourceBBox.x + sourceBBox.width / 2;
6216
+ const sourceCenterY = sourceBBox.y + sourceBBox.height / 2;
6217
+ const targetCenterX = targetBBox.x + targetBBox.width / 2;
6218
+ const targetCenterY = targetBBox.y + targetBBox.height / 2;
6219
+ const scaleX = targetBBox.width / (sourceBBox.width || 1);
6220
+ const scaleY = targetBBox.height / (sourceBBox.height || 1);
6221
+ gsap5.set(copyElement, {
6222
+ transformOrigin: `${sourceCenterX}px ${sourceCenterY}px`
6223
+ });
6224
+ timeline.add(copyElement, {
6225
+ scaleX: isFinite(scaleX) ? scaleX : 1,
6226
+ scaleY: isFinite(scaleY) ? scaleY : 1,
6227
+ x: targetCenterX - sourceCenterX,
6228
+ y: targetCenterY - sourceCenterY,
5419
6229
  opacity: 0,
5420
6230
  duration,
5421
6231
  ease: getGSAPEasing(easing2),
5422
6232
  delay,
5423
6233
  onComplete: () => {
5424
- sourceElement.remove();
6234
+ copyElement.remove();
6235
+ gsap5.set(targetElement, { opacity: 1 });
5425
6236
  }
5426
6237
  }, startTime);
5427
- timeline.add(targetElement, {
5428
- opacity: 1,
5429
- duration,
5430
- ease: getGSAPEasing(easing2),
5431
- delay
5432
- }, startTime);
5433
6238
  }
5434
6239
  };
5435
6240
  }
5436
6241
 
5437
6242
  // src/animate/animations/move.ts
5438
6243
  init_timeline();
5439
- import { gsap as gsap4 } from "gsap";
6244
+ import { gsap as gsap6 } from "gsap";
5440
6245
  import { MotionPathPlugin } from "gsap/MotionPathPlugin";
5441
6246
  if (typeof window !== "undefined") {
5442
- gsap4.registerPlugin(MotionPathPlugin);
6247
+ gsap6.registerPlugin(MotionPathPlugin);
5443
6248
  }
5444
6249
  function Shift(target, offset, options = {}) {
5445
6250
  const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0 } = options;
@@ -5515,7 +6320,7 @@ function MoveAlongPath(target, path2, options = {}) {
5515
6320
  console.warn("MoveAlongPath: \u65E0\u6CD5\u83B7\u53D6\u8DEF\u5F84\u6570\u636E");
5516
6321
  return;
5517
6322
  }
5518
- gsap4.set(pathElement, { opacity: 0 });
6323
+ gsap6.set(pathElement, { opacity: 0 });
5519
6324
  }
5520
6325
  timeline.add(element, {
5521
6326
  motionPath: {
@@ -5541,12 +6346,12 @@ function Rotate(target, angle3, options = {}) {
5541
6346
  const element = scene.getElement(target);
5542
6347
  if (!element) return;
5543
6348
  if (aboutPoint) {
5544
- gsap4.set(element, {
6349
+ gsap6.set(element, {
5545
6350
  transformOrigin: `${aboutPoint[0]}px ${aboutPoint[1]}px`
5546
6351
  });
5547
6352
  } else {
5548
6353
  const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
5549
- gsap4.set(element, {
6354
+ gsap6.set(element, {
5550
6355
  transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
5551
6356
  });
5552
6357
  }
@@ -5584,12 +6389,12 @@ function Scale(target, factor, options = {}) {
5584
6389
  const element = scene.getElement(target);
5585
6390
  if (!element) return;
5586
6391
  if (aboutPoint) {
5587
- gsap4.set(element, {
6392
+ gsap6.set(element, {
5588
6393
  transformOrigin: `${aboutPoint[0]}px ${aboutPoint[1]}px`
5589
6394
  });
5590
6395
  } else {
5591
6396
  const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
5592
- gsap4.set(element, {
6397
+ gsap6.set(element, {
5593
6398
  transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
5594
6399
  });
5595
6400
  }
@@ -5758,7 +6563,7 @@ function FadeToColor(target, color, options = {}) {
5758
6563
 
5759
6564
  // src/animate/animations/indicate.ts
5760
6565
  init_timeline();
5761
- import { gsap as gsap5 } from "gsap";
6566
+ import { gsap as gsap7 } from "gsap";
5762
6567
  function Indicate(target, options = {}) {
5763
6568
  const {
5764
6569
  duration = 0.5,
@@ -5778,7 +6583,7 @@ function Indicate(target, options = {}) {
5778
6583
  const originalFill = (_a = element.getAttribute("fill")) != null ? _a : "";
5779
6584
  const originalStroke = (_b = element.getAttribute("stroke")) != null ? _b : "";
5780
6585
  const bbox = ((_c = element.getBBox) == null ? void 0 : _c.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
5781
- gsap5.set(element, {
6586
+ gsap7.set(element, {
5782
6587
  transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
5783
6588
  });
5784
6589
  timeline.add(element, {
@@ -5851,7 +6656,7 @@ function Circumscribe(target, options = {}) {
5851
6656
  const h = parseFloat(circumscribeElement.getAttribute("height") || "0");
5852
6657
  length2 = (w + h) * 2;
5853
6658
  }
5854
- gsap5.set(circumscribeElement, {
6659
+ gsap7.set(circumscribeElement, {
5855
6660
  strokeDasharray: length2,
5856
6661
  strokeDashoffset: length2,
5857
6662
  opacity: 0
@@ -5890,7 +6695,7 @@ function Wiggle(target, options = {}) {
5890
6695
  const element = scene.getElement(target);
5891
6696
  if (!element) return;
5892
6697
  const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
5893
- gsap5.set(element, {
6698
+ gsap7.set(element, {
5894
6699
  transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
5895
6700
  });
5896
6701
  const wiggleDuration = duration / nWiggles;
@@ -5952,7 +6757,7 @@ function Flash(target, options = {}) {
5952
6757
  line3.setAttribute("stroke", color);
5953
6758
  line3.setAttribute("stroke-width", "2");
5954
6759
  line3.setAttribute("stroke-linecap", "round");
5955
- gsap5.set(line3, { opacity: 0 });
6760
+ gsap7.set(line3, { opacity: 0 });
5956
6761
  flashGroup.appendChild(line3);
5957
6762
  timeline.add(line3, {
5958
6763
  attr: { x2, y2 },
@@ -6016,7 +6821,7 @@ function ShowPassingFlash(target, options = {}) {
6016
6821
  flashPath.setAttribute("stroke", `url(#${gradientId})`);
6017
6822
  flashPath.setAttribute("fill", "none");
6018
6823
  flashPath.setAttribute("stroke-width", "4");
6019
- gsap5.set(flashPath, {
6824
+ gsap7.set(flashPath, {
6020
6825
  strokeDasharray: `${length2 * 0.1} ${length2 * 0.9}`,
6021
6826
  strokeDashoffset: length2
6022
6827
  });
@@ -6080,7 +6885,7 @@ function ApplyWave(target, options = {}) {
6080
6885
  const element = scene.getElement(target);
6081
6886
  if (!element) return;
6082
6887
  const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
6083
- gsap5.set(element, {
6888
+ gsap7.set(element, {
6084
6889
  transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
6085
6890
  });
6086
6891
  const proxy = { t: 0 };
@@ -6093,13 +6898,13 @@ function ApplyWave(target, options = {}) {
6093
6898
  const t = proxy.t;
6094
6899
  const wave = Math.sin(t * Math.PI * 2 * frequency) * amplitude * (1 - t);
6095
6900
  if (direction === "horizontal") {
6096
- gsap5.set(element, { x: wave });
6901
+ gsap7.set(element, { x: wave });
6097
6902
  } else {
6098
- gsap5.set(element, { y: wave });
6903
+ gsap7.set(element, { y: wave });
6099
6904
  }
6100
6905
  },
6101
6906
  onComplete: () => {
6102
- gsap5.set(element, { x: 0, y: 0 });
6907
+ gsap7.set(element, { x: 0, y: 0 });
6103
6908
  }
6104
6909
  }, startTime);
6105
6910
  }
@@ -6120,7 +6925,7 @@ function FocusOn(target, options = {}) {
6120
6925
  const element = scene.getElement(target);
6121
6926
  if (!element) return;
6122
6927
  const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
6123
- gsap5.set(element, {
6928
+ gsap7.set(element, {
6124
6929
  transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
6125
6930
  });
6126
6931
  const overlay = document.createElementNS("http://www.w3.org/2000/svg", "rect");
@@ -6129,7 +6934,7 @@ function FocusOn(target, options = {}) {
6129
6934
  overlay.setAttribute("width", "100%");
6130
6935
  overlay.setAttribute("height", "100%");
6131
6936
  overlay.setAttribute("fill", "#000000");
6132
- gsap5.set(overlay, { opacity: 0 });
6937
+ gsap7.set(overlay, { opacity: 0 });
6133
6938
  (_b = element.parentNode) == null ? void 0 : _b.insertBefore(overlay, element);
6134
6939
  timeline.add(overlay, {
6135
6940
  opacity: dimSurroundings,
@@ -6173,10 +6978,10 @@ function SpiralIn(target, options = {}) {
6173
6978
  const element = scene.getElement(target);
6174
6979
  if (!element) return;
6175
6980
  const bbox = ((_a = element.getBBox) == null ? void 0 : _a.call(element)) || { x: 0, y: 0, width: 0, height: 0 };
6176
- gsap5.set(element, {
6981
+ gsap7.set(element, {
6177
6982
  transformOrigin: `${bbox.x + bbox.width / 2}px ${bbox.y + bbox.height / 2}px`
6178
6983
  });
6179
- gsap5.set(element, {
6984
+ gsap7.set(element, {
6180
6985
  x: startDistance,
6181
6986
  y: 0,
6182
6987
  rotation: 0,
@@ -6195,7 +7000,7 @@ function SpiralIn(target, options = {}) {
6195
7000
  const x = Math.cos(angle3) * distance2;
6196
7001
  const y = Math.sin(angle3) * distance2;
6197
7002
  const rotation = angle3 * (180 / Math.PI);
6198
- gsap5.set(element, {
7003
+ gsap7.set(element, {
6199
7004
  x,
6200
7005
  y,
6201
7006
  rotation,
@@ -6203,7 +7008,7 @@ function SpiralIn(target, options = {}) {
6203
7008
  });
6204
7009
  },
6205
7010
  onComplete: () => {
6206
- gsap5.set(element, { x: 0, y: 0, rotation: 0, opacity: 1 });
7011
+ gsap7.set(element, { x: 0, y: 0, rotation: 0, opacity: 1 });
6207
7012
  }
6208
7013
  }, startTime);
6209
7014
  }
@@ -6236,13 +7041,13 @@ function PhaseFlow(target, options = {}) {
6236
7041
  const [newX, newY] = phaseFunc(cx, cy, proxy.t);
6237
7042
  const offsetX = newX - cx;
6238
7043
  const offsetY = newY - cy;
6239
- gsap5.set(element, {
7044
+ gsap7.set(element, {
6240
7045
  x: offsetX,
6241
7046
  y: offsetY
6242
7047
  });
6243
7048
  },
6244
7049
  onComplete: () => {
6245
- gsap5.set(element, { x: 0, y: 0 });
7050
+ gsap7.set(element, { x: 0, y: 0 });
6246
7051
  }
6247
7052
  }, startTime);
6248
7053
  }
@@ -6251,6 +7056,8 @@ function PhaseFlow(target, options = {}) {
6251
7056
 
6252
7057
  // src/animate/animations/composition.ts
6253
7058
  init_core();
7059
+ import { gsap as gsap8 } from "gsap";
7060
+ init_timeline();
6254
7061
  function AnimationGroup(animations, options = {}) {
6255
7062
  var _a, _b;
6256
7063
  const { lagRatio = 0 } = options;
@@ -6305,16 +7112,61 @@ function Wait(duration = 1) {
6305
7112
  }
6306
7113
  };
6307
7114
  }
6308
- function ApplyMethod(target, method, options = {}) {
6309
- const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0 } = options;
7115
+ function ApplyMethod(target, methodOrName, argsOrOptions, options = {}) {
7116
+ let method;
7117
+ let config;
7118
+ if (typeof methodOrName === "string") {
7119
+ const methodName = methodOrName;
7120
+ const args = argsOrOptions || [];
7121
+ config = options;
7122
+ method = (d) => {
7123
+ const fn = d[methodName];
7124
+ if (typeof fn === "function") {
7125
+ return fn.apply(d, args);
7126
+ }
7127
+ console.warn(`Method "${methodName}" not found on Diagram`);
7128
+ return d;
7129
+ };
7130
+ } else {
7131
+ method = methodOrName;
7132
+ config = argsOrOptions || {};
7133
+ }
7134
+ const { duration = 0.5, easing: easing2 = "easeInOut", delay = 0 } = config;
6310
7135
  const targetDiagram = method(target);
6311
7136
  return {
6312
7137
  duration,
6313
7138
  target,
6314
7139
  execute(scene, timeline, startTime) {
6315
- import("./transform-4WYIJSLH.mjs").then(({ Transform: Transform2 }) => {
6316
- Transform2(target, targetDiagram, { duration, easing: easing2, delay }).execute(scene, timeline, startTime);
7140
+ var _a, _b, _c, _d, _e, _f;
7141
+ const element = scene.getOrCreateElement(target);
7142
+ if (!element) return;
7143
+ const sourceBounds = target.bounds();
7144
+ const targetBounds = targetDiagram.bounds();
7145
+ const sourceCenter = [
7146
+ sourceBounds.x + sourceBounds.width / 2,
7147
+ sourceBounds.y + sourceBounds.height / 2
7148
+ ];
7149
+ const targetCenter = [
7150
+ targetBounds.x + targetBounds.width / 2,
7151
+ targetBounds.y + targetBounds.height / 2
7152
+ ];
7153
+ const translateX = ((_a = targetCenter[0]) != null ? _a : 0) - ((_b = sourceCenter[0]) != null ? _b : 0);
7154
+ const translateY = ((_c = targetCenter[1]) != null ? _c : 0) - ((_d = sourceCenter[1]) != null ? _d : 0);
7155
+ const scaleX = targetBounds.width / (sourceBounds.width || 1);
7156
+ const scaleY = targetBounds.height / (sourceBounds.height || 1);
7157
+ gsap8.set(element, {
7158
+ transformOrigin: `${(_e = sourceCenter[0]) != null ? _e : 0}px ${(_f = sourceCenter[1]) != null ? _f : 0}px`
6317
7159
  });
7160
+ timeline.add(element, {
7161
+ x: translateX,
7162
+ y: -translateY,
7163
+ // SVG Y 轴翻转
7164
+ scaleX: isFinite(scaleX) ? scaleX : 1,
7165
+ scaleY: isFinite(scaleY) ? scaleY : 1,
7166
+ duration,
7167
+ ease: getGSAPEasing(easing2),
7168
+ delay
7169
+ }, startTime);
6318
7170
  }
6319
7171
  };
6320
7172
  }
@@ -6380,7 +7232,7 @@ function transformPathByHomotopy(d, homotopyFn, t) {
6380
7232
 
6381
7233
  // src/animate/animations/text.ts
6382
7234
  init_timeline();
6383
- import { gsap as gsap6 } from "gsap";
7235
+ import { gsap as gsap9 } from "gsap";
6384
7236
  function AddTextLetterByLetter(target, options = {}) {
6385
7237
  const { duration = 1, easing: easing2 = "linear", delay = 0, timePerChar } = options;
6386
7238
  return {
@@ -6399,7 +7251,7 @@ function AddTextLetterByLetter(target, options = {}) {
6399
7251
  chars.forEach((char, i) => {
6400
7252
  const tspan = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
6401
7253
  tspan.textContent = char;
6402
- gsap6.set(tspan, { opacity: 0 });
7254
+ gsap9.set(tspan, { opacity: 0 });
6403
7255
  text2.appendChild(tspan);
6404
7256
  const charDelay = i * charDuration;
6405
7257
  timeline.add(tspan, {
@@ -6476,7 +7328,7 @@ function Typewriter(target, options = {}) {
6476
7328
  cursorTspan.textContent = cursorChar;
6477
7329
  cursorTspan.setAttribute("class", "typewriter-cursor");
6478
7330
  text2.appendChild(cursorTspan);
6479
- gsap6.to(cursorTspan, {
7331
+ gsap9.to(cursorTspan, {
6480
7332
  opacity: 0,
6481
7333
  duration: cursorBlinkInterval,
6482
7334
  repeat: -1,
@@ -6498,8 +7350,8 @@ function Typewriter(target, options = {}) {
6498
7350
  });
6499
7351
  if (cursorTspan) {
6500
7352
  timeline.call(() => {
6501
- gsap6.killTweensOf(cursorTspan);
6502
- gsap6.to(cursorTspan, {
7353
+ gsap9.killTweensOf(cursorTspan);
7354
+ gsap9.to(cursorTspan, {
6503
7355
  opacity: 0,
6504
7356
  duration: 0.3,
6505
7357
  delay: 1
@@ -6712,7 +7564,7 @@ function CameraSetFrame(camera, targetFrame, options = {}) {
6712
7564
 
6713
7565
  // src/animate/animations/traced-path.ts
6714
7566
  init_core();
6715
- import { gsap as gsap7 } from "gsap";
7567
+ import { gsap as gsap10 } from "gsap";
6716
7568
  function TracedPath(target, config = {}) {
6717
7569
  const {
6718
7570
  strokeColor = "#EA580C",
@@ -6753,11 +7605,10 @@ function TracedPath(target, config = {}) {
6753
7605
  const stop = () => {
6754
7606
  state.active = false;
6755
7607
  };
6756
- return {
6757
- diagram: traceDiagram,
6758
- updater,
6759
- stop
6760
- };
7608
+ const result = traceDiagram;
7609
+ result.updater = updater;
7610
+ result.stop = stop;
7611
+ return result;
6761
7612
  }
6762
7613
  function TracedPathAnimation(target, config = {}) {
6763
7614
  const {
@@ -6821,7 +7672,7 @@ function GrowArrow(arrowDiagram, config = {}) {
6821
7672
  lines.forEach((line3) => {
6822
7673
  var _a;
6823
7674
  const length2 = ((_a = line3.getTotalLength) == null ? void 0 : _a.call(line3)) || 100;
6824
- gsap7.set(line3, {
7675
+ gsap10.set(line3, {
6825
7676
  strokeDasharray: length2,
6826
7677
  strokeDashoffset: length2
6827
7678
  });
@@ -6838,7 +7689,7 @@ function GrowArrow(arrowDiagram, config = {}) {
6838
7689
  // src/animate/animations/p1-animations.ts
6839
7690
  init_core();
6840
7691
  init_complex();
6841
- import { gsap as gsap8 } from "gsap";
7692
+ import { gsap as gsap11 } from "gsap";
6842
7693
  function AddTextWordByWord(textDiagram, config = {}) {
6843
7694
  const { timePerWord = 0.2, duration = 1 } = config;
6844
7695
  return {
@@ -6849,7 +7700,7 @@ function AddTextWordByWord(textDiagram, config = {}) {
6849
7700
  if (!element) return;
6850
7701
  const textElement = element.querySelector("text") || element;
6851
7702
  if (!(textElement instanceof SVGTextElement)) {
6852
- gsap8.set(element, { opacity: 0 });
7703
+ gsap11.set(element, { opacity: 0 });
6853
7704
  timeline.add(element, { opacity: 1, duration }, startTime);
6854
7705
  return;
6855
7706
  }
@@ -6875,18 +7726,19 @@ function AddTextWordByWord(textDiagram, config = {}) {
6875
7726
  }
6876
7727
  };
6877
7728
  }
6878
- function ShowIncreasingSubsets(group4, config = {}) {
7729
+ function ShowIncreasingSubsets(groupOrArray, config = {}) {
6879
7730
  const { duration = 1 } = config;
7731
+ const targetGroup = Array.isArray(groupOrArray) ? group(...groupOrArray) : groupOrArray;
6880
7732
  return {
6881
7733
  duration,
6882
- target: group4,
7734
+ target: targetGroup,
6883
7735
  execute(scene, timeline, startTime) {
6884
- const element = scene.getOrCreateElement(group4);
7736
+ const element = scene.getOrCreateElement(targetGroup);
6885
7737
  if (!element) return;
6886
7738
  const children = Array.from(element.children);
6887
7739
  if (children.length === 0) return;
6888
7740
  const timePerChild = duration / children.length;
6889
- children.forEach((child) => gsap8.set(child, { opacity: 0 }));
7741
+ children.forEach((child) => gsap11.set(child, { opacity: 0 }));
6890
7742
  children.forEach((child, i) => {
6891
7743
  timeline.add(child, { opacity: 1, duration: timePerChild * 0.5 }, startTime + i * timePerChild);
6892
7744
  });
@@ -6904,7 +7756,7 @@ function ChangingDecimal(textDiagram, targetValue, config = {}) {
6904
7756
  const textElement = element.querySelector("text") || element;
6905
7757
  const obj = { value: startValue };
6906
7758
  timeline.call(() => {
6907
- gsap8.to(obj, {
7759
+ gsap11.to(obj, {
6908
7760
  value: targetValue,
6909
7761
  duration,
6910
7762
  ease: "none",
@@ -6935,7 +7787,7 @@ function Broadcast(source, config = {}) {
6935
7787
  const waveDiagram = circle(0.01).stroke(color).strokeWidth(0.05).fill("none").translate(cx, cy);
6936
7788
  const waveElement = scene.getOrCreateElement(waveDiagram);
6937
7789
  if (!waveElement) continue;
6938
- gsap8.set(waveElement, { opacity: 1 });
7790
+ gsap11.set(waveElement, { opacity: 1 });
6939
7791
  const waveStartTime = startTime + i * waveDelay;
6940
7792
  timeline.add(waveElement, {
6941
7793
  attr: { r: maxRadius },
@@ -6968,7 +7820,7 @@ function ApplyFunction(diagram, fn, config = {}) {
6968
7820
  }
6969
7821
  const obj = { progress: 0 };
6970
7822
  timeline.call(() => {
6971
- gsap8.to(obj, {
7823
+ gsap11.to(obj, {
6972
7824
  progress: 1,
6973
7825
  duration,
6974
7826
  ease: "power2.inOut",
@@ -7007,7 +7859,7 @@ function Restore(diagram, config = {}) {
7007
7859
  const currentElement = scene.getElement(diagram);
7008
7860
  const targetElement = scene.getOrCreateElement(savedState);
7009
7861
  if (!currentElement || !targetElement) return;
7010
- gsap8.set(targetElement, { opacity: 0 });
7862
+ gsap11.set(targetElement, { opacity: 0 });
7011
7863
  timeline.add(currentElement, { opacity: 0, duration: duration / 2 }, startTime);
7012
7864
  timeline.add(targetElement, { opacity: 1, duration: duration / 2 }, startTime + duration / 2);
7013
7865
  }
@@ -7081,7 +7933,7 @@ var Axes = class {
7081
7933
  );
7082
7934
  }
7083
7935
  for (let y = yMin; y <= yMax; y += yStep) {
7084
- const py = oy - y * yScale;
7936
+ const py = oy + y * yScale;
7085
7937
  diagrams.push(
7086
7938
  line([ox + xMin * xScale, py], [ox + xMax * xScale, py]).stroke(gridColor).strokeWidth(gridStrokeWidth)
7087
7939
  );
@@ -7090,8 +7942,8 @@ var Axes = class {
7090
7942
  const xAxisStart = [ox + xMin * xScale, oy];
7091
7943
  const xAxisEnd = [ox + xMax * xScale, oy];
7092
7944
  diagrams.push(arrow(xAxisStart, xAxisEnd, { headSize }).stroke(axisColor).strokeWidth(strokeWidth));
7093
- const yAxisStart = [ox, oy - yMin * yScale];
7094
- const yAxisEnd = [ox, oy - yMax * yScale];
7945
+ const yAxisStart = [ox, oy + yMin * yScale];
7946
+ const yAxisEnd = [ox, oy + yMax * yScale];
7095
7947
  diagrams.push(arrow(yAxisStart, yAxisEnd, { headSize }).stroke(axisColor).strokeWidth(strokeWidth));
7096
7948
  if (showTicks || showLabels) {
7097
7949
  for (let x = xMin; x <= xMax; x += xStep) {
@@ -7110,7 +7962,7 @@ var Axes = class {
7110
7962
  }
7111
7963
  for (let y = yMin; y <= yMax; y += yStep) {
7112
7964
  if (y === 0) continue;
7113
- const py = oy - y * yScale;
7965
+ const py = oy + y * yScale;
7114
7966
  if (showTicks) {
7115
7967
  diagrams.push(
7116
7968
  line([ox - tickSize, py], [ox + tickSize, py]).stroke(axisColor).strokeWidth(strokeWidth)
@@ -7137,7 +7989,7 @@ var Axes = class {
7137
7989
  const yScale = yLength / (yRange[1] - yRange[0]);
7138
7990
  return [
7139
7991
  origin[0] + x * xScale,
7140
- origin[1] - yVal * yScale
7992
+ origin[1] + yVal * yScale
7141
7993
  // Y 轴向上为正
7142
7994
  ];
7143
7995
  }
@@ -7148,7 +8000,8 @@ var Axes = class {
7148
8000
  const yScale = yLength / (yRange[1] - yRange[0]);
7149
8001
  return [
7150
8002
  (px - origin[0]) / xScale,
7151
- -(pyVal - origin[1]) / yScale
8003
+ (pyVal - origin[1]) / yScale
8004
+ // Y 轴向上为正
7152
8005
  ];
7153
8006
  }
7154
8007
  /** 绑制函数图像 */
@@ -7435,9 +8288,9 @@ var LinearTransformationScene = class extends Scene {
7435
8288
  ];
7436
8289
  void _transformFn;
7437
8290
  return new Promise((resolve) => {
7438
- import("gsap").then(({ gsap: gsap9 }) => {
8291
+ import("gsap").then(({ gsap: gsap12 }) => {
7439
8292
  const obj = { t: 0 };
7440
- gsap9.to(obj, {
8293
+ gsap12.to(obj, {
7441
8294
  t: 1,
7442
8295
  duration,
7443
8296
  ease: "power2.inOut",
@@ -7879,8 +8732,10 @@ var Interactive = class {
7879
8732
  const rect2 = this.svg.getBoundingClientRect();
7880
8733
  const clientX = "touches" in e ? (_b = (_a = e.touches[0]) == null ? void 0 : _a.clientX) != null ? _b : 0 : e.clientX;
7881
8734
  const clientY = "touches" in e ? (_d = (_c = e.touches[0]) == null ? void 0 : _c.clientY) != null ? _d : 0 : e.clientY;
7882
- let newX = (clientX - rect2.left) * (this.options.width / rect2.width);
7883
- let newY = (clientY - rect2.top) * (this.options.height / rect2.height);
8735
+ const svgWidth = this.svg.viewBox.baseVal.width || this.options.width;
8736
+ const svgHeight = this.svg.viewBox.baseVal.height || this.options.height;
8737
+ let newX = (clientX - rect2.left) * (svgWidth / rect2.width);
8738
+ let newY = (clientY - rect2.top) * (svgHeight / rect2.height);
7884
8739
  if (constraint) {
7885
8740
  [newX, newY] = constraint([newX, newY]);
7886
8741
  }
@@ -8902,19 +9757,19 @@ var Table = class {
8902
9757
  } else {
8903
9758
  this._colWidths = Array(numCols).fill(80);
8904
9759
  }
8905
- if (config.hLines === true) {
8906
- this._hLines = Array.from({ length: numRows + 1 }, (_, i) => i);
9760
+ if (config.hLines === false) {
9761
+ this._hLines = [];
8907
9762
  } else if (Array.isArray(config.hLines)) {
8908
9763
  this._hLines = config.hLines;
8909
9764
  } else {
8910
- this._hLines = [];
9765
+ this._hLines = Array.from({ length: numRows + 1 }, (_, i) => i);
8911
9766
  }
8912
- if (config.vLines === true) {
8913
- this._vLines = Array.from({ length: numCols + 1 }, (_, i) => i);
9767
+ if (config.vLines === false) {
9768
+ this._vLines = [];
8914
9769
  } else if (Array.isArray(config.vLines)) {
8915
9770
  this._vLines = config.vLines;
8916
9771
  } else {
8917
- this._vLines = [];
9772
+ this._vLines = Array.from({ length: numCols + 1 }, (_, i) => i);
8918
9773
  }
8919
9774
  this._headerRow = (_a = config.headerRow) != null ? _a : false;
8920
9775
  this._headerCol = (_b = config.headerCol) != null ? _b : false;
@@ -8935,11 +9790,12 @@ var Table = class {
8935
9790
  buildCells() {
8936
9791
  var _a, _b;
8937
9792
  const cells = [];
8938
- let y = 0;
9793
+ let y = this._totalHeight;
8939
9794
  for (let row = 0; row < this._data.length; row++) {
8940
9795
  const rowCells = [];
8941
9796
  let x = 0;
8942
9797
  const rowHeight = (_a = this._rowHeights[row]) != null ? _a : 30;
9798
+ y -= rowHeight / 2;
8943
9799
  for (let col = 0; col < this._data[row].length; col++) {
8944
9800
  const colWidth = (_b = this._colWidths[col]) != null ? _b : 80;
8945
9801
  const cellData = this._data[row][col];
@@ -8959,14 +9815,14 @@ var Table = class {
8959
9815
  row,
8960
9816
  col,
8961
9817
  x: x + colWidth / 2,
8962
- y: y + rowHeight / 2,
9818
+ y,
8963
9819
  width: colWidth,
8964
9820
  height: rowHeight
8965
9821
  });
8966
9822
  x += colWidth;
8967
9823
  }
8968
9824
  cells.push(rowCells);
8969
- y += rowHeight;
9825
+ y -= rowHeight / 2;
8970
9826
  }
8971
9827
  return cells;
8972
9828
  }
@@ -9057,22 +9913,22 @@ var Table = class {
9057
9913
  var _a, _b, _c, _d, _e;
9058
9914
  const elements = [];
9059
9915
  if (this._alternateRowColor) {
9060
- let y2 = 0;
9916
+ let y2 = this._totalHeight;
9061
9917
  for (let row = 0; row < this._data.length; row++) {
9062
9918
  const rowHeight = (_a = this._rowHeights[row]) != null ? _a : 30;
9919
+ y2 -= rowHeight;
9063
9920
  if (row % 2 === 1) {
9064
9921
  elements.push(
9065
9922
  rect(this._totalWidth, rowHeight).fill(this._alternateRowColor).translate(this._totalWidth / 2, y2 + rowHeight / 2)
9066
9923
  );
9067
9924
  }
9068
- y2 += rowHeight;
9069
9925
  }
9070
9926
  }
9071
9927
  if (this._headerBackground) {
9072
9928
  if (this._headerRow) {
9073
9929
  const headerHeight = (_b = this._rowHeights[0]) != null ? _b : 30;
9074
9930
  elements.push(
9075
- rect(this._totalWidth, headerHeight).fill(this._headerBackground).translate(this._totalWidth / 2, headerHeight / 2)
9931
+ rect(this._totalWidth, headerHeight).fill(this._headerBackground).translate(this._totalWidth / 2, this._totalHeight - headerHeight / 2)
9076
9932
  );
9077
9933
  }
9078
9934
  if (this._headerCol) {
@@ -9082,7 +9938,7 @@ var Table = class {
9082
9938
  );
9083
9939
  }
9084
9940
  }
9085
- let y = 0;
9941
+ let y = this._totalHeight;
9086
9942
  for (let i = 0; i <= this._data.length; i++) {
9087
9943
  if (this._hLines.includes(i)) {
9088
9944
  elements.push(
@@ -9090,7 +9946,7 @@ var Table = class {
9090
9946
  );
9091
9947
  }
9092
9948
  if (i < this._data.length) {
9093
- y += (_d = this._rowHeights[i]) != null ? _d : 30;
9949
+ y -= (_d = this._rowHeights[i]) != null ? _d : 30;
9094
9950
  }
9095
9951
  }
9096
9952
  let x = 0;
@@ -13975,6 +14831,1067 @@ import * as THREE18 from "three";
13975
14831
  // src/webgl/overlay/index.ts
13976
14832
  import * as THREE19 from "three";
13977
14833
  import { CSS2DRenderer, CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer.js";
14834
+
14835
+ // src/showcase/Showcase.tsx
14836
+ import React, { useCallback as useCallback3, useMemo } from "react";
14837
+
14838
+ // src/showcase/hooks/useShowcase.ts
14839
+ import { useRef, useEffect, useState, useCallback } from "react";
14840
+
14841
+ // src/showcase/ShowcaseCore.ts
14842
+ init_core();
14843
+
14844
+ // src/showcase/utils/scope-api.ts
14845
+ var scope_api_exports = {};
14846
+ __export(scope_api_exports, {
14847
+ AddTextLetterByLetter: () => AddTextLetterByLetter,
14848
+ AddTextWordByWord: () => AddTextWordByWord,
14849
+ AnimationGroup: () => AnimationGroup,
14850
+ ApplyComplexFunction: () => ApplyComplexFunction,
14851
+ ApplyFunction: () => ApplyFunction,
14852
+ ApplyMethod: () => ApplyMethod,
14853
+ ApplyWave: () => ApplyWave,
14854
+ Axes: () => Axes,
14855
+ Blink: () => Blink,
14856
+ Broadcast: () => Broadcast,
14857
+ Camera: () => Camera,
14858
+ CameraAutoZoom: () => CameraAutoZoom,
14859
+ CameraMove: () => CameraMove,
14860
+ CameraReset: () => CameraReset,
14861
+ CameraSetFrame: () => CameraSetFrame,
14862
+ CameraZoom: () => CameraZoom,
14863
+ ChangingDecimal: () => ChangingDecimal,
14864
+ Circumscribe: () => Circumscribe,
14865
+ ClockwiseTransform: () => ClockwiseTransform,
14866
+ ColorScales: () => ColorScales,
14867
+ Colors: () => Colors,
14868
+ CounterclockwiseTransform: () => CounterclockwiseTransform,
14869
+ Create: () => Create,
14870
+ CyclicReplace: () => CyclicReplace,
14871
+ DEGREES: () => DEGREES,
14872
+ DL: () => DL,
14873
+ DOWN: () => DOWN,
14874
+ DR: () => DR,
14875
+ DiGraph: () => DiGraph,
14876
+ Diagram: () => Diagram,
14877
+ Dir: () => Dir,
14878
+ DrawBorderThenFill: () => DrawBorderThenFill,
14879
+ FadeIn: () => FadeIn,
14880
+ FadeInFrom: () => FadeInFrom,
14881
+ FadeInFromDown: () => FadeInFromDown,
14882
+ FadeInFromLeft: () => FadeInFromLeft,
14883
+ FadeInFromRight: () => FadeInFromRight,
14884
+ FadeInFromUp: () => FadeInFromUp,
14885
+ FadeOut: () => FadeOut,
14886
+ FadeOutTo: () => FadeOutTo,
14887
+ FadeToColor: () => FadeToColor,
14888
+ FadeTransform: () => FadeTransform,
14889
+ Flash: () => Flash,
14890
+ FocusOn: () => FocusOn,
14891
+ Graph: () => Graph,
14892
+ GrowArrow: () => GrowArrow,
14893
+ GrowFromCenter: () => GrowFromCenter,
14894
+ GrowFromEdge: () => GrowFromEdge,
14895
+ GrowFromPoint: () => GrowFromPoint,
14896
+ Homotopy: () => Homotopy,
14897
+ IDENTITY: () => IDENTITY,
14898
+ Indicate: () => Indicate,
14899
+ Interactive: () => Interactive,
14900
+ LEFT: () => LEFT,
14901
+ LaggedStart: () => LaggedStart,
14902
+ LaggedStartMap: () => LaggedStartMap,
14903
+ ManimColor: () => ManimColor,
14904
+ MatrixDisplay: () => MatrixDisplay,
14905
+ Morphing: () => Morphing,
14906
+ MoveAlongPath: () => MoveAlongPath,
14907
+ MoveTo: () => MoveTo,
14908
+ MoveToTarget: () => MoveToTarget,
14909
+ MovingCamera: () => MovingCamera,
14910
+ NumberLine: () => NumberLine,
14911
+ NumberPlane: () => NumberPlane,
14912
+ ORIGIN: () => ORIGIN,
14913
+ PI: () => PI,
14914
+ PhaseFlow: () => PhaseFlow,
14915
+ PolarAxes: () => PolarAxes,
14916
+ RIGHT: () => RIGHT,
14917
+ RemoveTextLetterByLetter: () => RemoveTextLetterByLetter,
14918
+ ReplacementTransform: () => ReplacementTransform,
14919
+ Restore: () => Restore,
14920
+ Rotate: () => Rotate,
14921
+ Rotating: () => Rotating,
14922
+ Scale: () => Scale,
14923
+ ScaleInPlace: () => ScaleInPlace,
14924
+ Scene: () => Scene,
14925
+ Shift: () => Shift,
14926
+ ShowIncreasingSubsets: () => ShowIncreasingSubsets,
14927
+ ShowPassingFlash: () => ShowPassingFlash,
14928
+ ShrinkToCenter: () => ShrinkToCenter,
14929
+ SpinInFromNothing: () => SpinInFromNothing,
14930
+ SpiralIn: () => SpiralIn,
14931
+ Succession: () => Succession,
14932
+ Swap: () => Swap,
14933
+ TAU: () => TAU,
14934
+ Table: () => Table,
14935
+ ThreeB1BColors: () => ThreeB1BColors,
14936
+ TracedPath: () => TracedPath,
14937
+ TracedPathAnimation: () => TracedPathAnimation,
14938
+ Transform: () => Transform,
14939
+ TransformFromCopy: () => TransformFromCopy,
14940
+ TransformMatchingShapes: () => TransformMatchingShapes,
14941
+ TransformMatchingTex: () => TransformMatchingTex,
14942
+ Typewriter: () => Typewriter,
14943
+ UL: () => UL,
14944
+ UP: () => UP,
14945
+ UR: () => UR,
14946
+ Uncreate: () => Uncreate,
14947
+ Unwrite: () => Unwrite,
14948
+ UpdateFromAlphaFunc: () => UpdateFromAlphaFunc,
14949
+ UpdateFromFunc: () => UpdateFromFunc,
14950
+ V2: () => V2,
14951
+ V3: () => V3,
14952
+ Wait: () => Wait,
14953
+ Wiggle: () => Wiggle,
14954
+ Write: () => Write,
14955
+ add: () => add,
14956
+ altitude: () => altitude,
14957
+ angle: () => angle,
14958
+ angleBetween: () => angleBetween,
14959
+ angleBisector: () => angleBisector,
14960
+ angleMarker: () => angleMarker,
14961
+ annularSector: () => annularSector,
14962
+ annulus: () => annulus,
14963
+ applyMatrix: () => applyMatrix,
14964
+ arc: () => arc,
14965
+ arcBetweenPoints: () => arcBetweenPoints,
14966
+ arrow: () => arrow,
14967
+ brace: () => brace,
14968
+ braceBetweenPoints: () => braceBetweenPoints,
14969
+ braceLabel: () => braceLabel,
14970
+ bulletedList: () => bulletedList,
14971
+ centroid: () => centroid,
14972
+ circle: () => circle,
14973
+ circleConstraint: () => circleConstraint,
14974
+ circleIntersections: () => circleIntersections,
14975
+ circumscribedCircle: () => circumscribedCircle,
14976
+ clamp: () => clamp,
14977
+ code: () => code,
14978
+ colorGradient: () => colorGradient,
14979
+ combine: () => combine,
14980
+ createCamera: () => createCamera,
14981
+ createInteractive: () => createInteractive,
14982
+ createMovingCamera: () => createMovingCamera,
14983
+ createTimeline: () => createTimeline,
14984
+ cross: () => cross,
14985
+ crossMark: () => crossMark,
14986
+ cubicBezier: () => cubicBezier,
14987
+ curvedArrow: () => curvedArrow,
14988
+ curvedDoubleArrow: () => curvedDoubleArrow,
14989
+ cutout: () => cutout,
14990
+ decimalMatrix: () => decimalMatrix,
14991
+ decimalTable: () => decimalTable,
14992
+ degToRad: () => degToRad,
14993
+ determinant: () => determinant,
14994
+ digraph: () => digraph,
14995
+ distance: () => distance,
14996
+ div: () => div,
14997
+ dot: () => dot2,
14998
+ doubleArrow: () => doubleArrow,
14999
+ easing: () => easing,
15000
+ elbow: () => elbow,
15001
+ ellipse: () => ellipse,
15002
+ equilateralTriangle: () => equilateralTriangle,
15003
+ footOfPerpendicular: () => footOfPerpendicular,
15004
+ functionConstraint: () => functionConstraint,
15005
+ getColor: () => getColor,
15006
+ graph: () => graph,
15007
+ gridConstraint: () => gridConstraint,
15008
+ group: () => group,
15009
+ inscribedCircle: () => inscribedCircle,
15010
+ integerMatrix: () => integerMatrix,
15011
+ integerTable: () => integerTable,
15012
+ interpolateColor: () => interpolateColor,
15013
+ labeledDot: () => labeledDot,
15014
+ length: () => length,
15015
+ lerp: () => lerp,
15016
+ lerpNumber: () => lerpNumber,
15017
+ line: () => line,
15018
+ lineConstraint: () => lineConstraint,
15019
+ lineIntersection: () => lineIntersection,
15020
+ mapRange: () => mapRange,
15021
+ markupText: () => markupText,
15022
+ mathTable: () => mathTable,
15023
+ matrix: () => matrix,
15024
+ matrixMultiply: () => matrixMultiply,
15025
+ median: () => median,
15026
+ midpoint: () => midpoint,
15027
+ mul: () => mul,
15028
+ normalize: () => normalize,
15029
+ orthocenter: () => orthocenter,
15030
+ paragraph: () => paragraph,
15031
+ parallelLine: () => parallelLine,
15032
+ path: () => path,
15033
+ pathFromString: () => pathFromString,
15034
+ perpendicular: () => perpendicular,
15035
+ perpendicularBisector: () => perpendicularBisector,
15036
+ perpendicularLine: () => perpendicularLine,
15037
+ polarConstraint: () => polarConstraint,
15038
+ polygon: () => polygon,
15039
+ polyline: () => polyline,
15040
+ quadraticBezier: () => quadraticBezier,
15041
+ radToDeg: () => radToDeg,
15042
+ rect: () => rect,
15043
+ rectConstraint: () => rectConstraint,
15044
+ reflect: () => reflect,
15045
+ reflectOverPoint: () => reflectOverPoint,
15046
+ reflectPoint: () => reflectPoint,
15047
+ reflectPointOverLine: () => reflectPointOverLine,
15048
+ regularPolygon: () => regularPolygon,
15049
+ regularPolygram: () => regularPolygram,
15050
+ renderToRough: () => renderToRough,
15051
+ renderToSVG: () => renderToSVG,
15052
+ rightAngleMarker: () => rightAngleMarker,
15053
+ rotate: () => rotate,
15054
+ rotationMatrix: () => rotationMatrix,
15055
+ roughPresets: () => roughPresets,
15056
+ sampleParametric: () => sampleParametric,
15057
+ scaleMatrix: () => scaleMatrix,
15058
+ sector: () => sector,
15059
+ square: () => square,
15060
+ star: () => star,
15061
+ sub: () => sub,
15062
+ table: () => table,
15063
+ tangentLine: () => tangentLine,
15064
+ tex: () => tex,
15065
+ text: () => text,
15066
+ toSVGString: () => toSVGString,
15067
+ translationMatrix: () => translationMatrix,
15068
+ triangle: () => triangle,
15069
+ vector: () => vector
15070
+ });
15071
+ init_math();
15072
+ init_core();
15073
+
15074
+ // src/showcase/utils/code-executor.ts
15075
+ function preprocessCode(code2) {
15076
+ return code2.split("\n").filter((line3) => {
15077
+ const trimmed = line3.trim();
15078
+ return !trimmed.startsWith("import ") && !trimmed.startsWith("export ");
15079
+ }).join("\n");
15080
+ }
15081
+ function detectRenderMode(code2) {
15082
+ const processedCode = preprocessCode(code2);
15083
+ if (processedCode.includes("scene.play") || processedCode.includes("scene.add") || /play\s*\(/.test(processedCode)) {
15084
+ return "animation";
15085
+ }
15086
+ if (/\bint\./.test(processedCode) || /\bint\[/.test(processedCode)) {
15087
+ return "interactive";
15088
+ }
15089
+ return "static";
15090
+ }
15091
+ async function executeCode(code2, svg, options) {
15092
+ const processedCode = preprocessCode(code2);
15093
+ const mode = detectRenderMode(processedCode);
15094
+ const diagrams = [];
15095
+ let sceneInstance = null;
15096
+ let interactiveInstance = null;
15097
+ let RegisteredSceneClass = null;
15098
+ const scope = __spreadProps(__spreadValues({}, scope_api_exports), {
15099
+ // draw 函数:收集静态图形
15100
+ draw: (diagram) => {
15101
+ diagrams.push(diagram);
15102
+ },
15103
+ // play 函数:注册 Scene 类
15104
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15105
+ play: (sceneClass) => {
15106
+ RegisteredSceneClass = sceneClass;
15107
+ },
15108
+ // int 代理:交互模式
15109
+ int: new Proxy({}, {
15110
+ get(_target, prop) {
15111
+ if (!interactiveInstance) {
15112
+ const Interactive2 = Interactive;
15113
+ if (Interactive2) {
15114
+ interactiveInstance = new Interactive2(
15115
+ svg.parentElement,
15116
+ { width: options.width, height: options.height }
15117
+ );
15118
+ }
15119
+ }
15120
+ return interactiveInstance == null ? void 0 : interactiveInstance[prop];
15121
+ }
15122
+ }),
15123
+ // SVG 元素
15124
+ svg,
15125
+ // 控制台
15126
+ console,
15127
+ // scene 对象(动画模式直接使用)
15128
+ scene: null
15129
+ });
15130
+ if (mode === "animation" && (processedCode.includes("scene.play") || processedCode.includes("scene.add"))) {
15131
+ class ShowcaseScene extends Scene {
15132
+ async construct() {
15133
+ }
15134
+ }
15135
+ sceneInstance = new ShowcaseScene();
15136
+ sceneInstance.setup(svg, {
15137
+ width: options.width,
15138
+ height: options.height,
15139
+ background: options.background || "#000"
15140
+ });
15141
+ scope.scene = sceneInstance;
15142
+ }
15143
+ try {
15144
+ const AsyncFunction = Object.getPrototypeOf(async function() {
15145
+ }).constructor;
15146
+ const fn = new AsyncFunction(
15147
+ "scope",
15148
+ `with (scope) {
15149
+ ${processedCode}
15150
+ }`
15151
+ );
15152
+ await fn(scope);
15153
+ if (RegisteredSceneClass && !sceneInstance) {
15154
+ const SceneClass = RegisteredSceneClass;
15155
+ const newScene = new SceneClass();
15156
+ newScene.setup(svg, {
15157
+ width: options.width,
15158
+ height: options.height,
15159
+ background: options.background || "#000"
15160
+ });
15161
+ await newScene.construct();
15162
+ sceneInstance = newScene;
15163
+ }
15164
+ if (sceneInstance) {
15165
+ sceneInstance.start();
15166
+ }
15167
+ return {
15168
+ mode,
15169
+ diagrams,
15170
+ scene: sceneInstance,
15171
+ interactive: interactiveInstance
15172
+ };
15173
+ } catch (error) {
15174
+ throw new Error(`\u4EE3\u7801\u6267\u884C\u9519\u8BEF: ${error.message}`);
15175
+ }
15176
+ }
15177
+
15178
+ // src/showcase/utils/export.ts
15179
+ function exportSVG(svg) {
15180
+ const serializer = new XMLSerializer();
15181
+ const svgString = serializer.serializeToString(svg);
15182
+ return `<?xml version="1.0" encoding="UTF-8"?>
15183
+ ${svgString}`;
15184
+ }
15185
+ async function exportJPG(svg, options = {}) {
15186
+ const { quality = 0.9 } = options;
15187
+ const bbox = svg.getBBox();
15188
+ const width = options.width || svg.clientWidth || bbox.width || 800;
15189
+ const height = options.height || svg.clientHeight || bbox.height || 450;
15190
+ const canvas = document.createElement("canvas");
15191
+ canvas.width = width;
15192
+ canvas.height = height;
15193
+ const ctx = canvas.getContext("2d");
15194
+ if (!ctx) {
15195
+ throw new Error("\u65E0\u6CD5\u521B\u5EFA Canvas \u4E0A\u4E0B\u6587");
15196
+ }
15197
+ const svgString = exportSVG(svg);
15198
+ const blob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
15199
+ const url = URL.createObjectURL(blob);
15200
+ return new Promise((resolve, reject) => {
15201
+ const img = new Image();
15202
+ img.onload = () => {
15203
+ ctx.fillStyle = "#ffffff";
15204
+ ctx.fillRect(0, 0, width, height);
15205
+ ctx.drawImage(img, 0, 0, width, height);
15206
+ URL.revokeObjectURL(url);
15207
+ canvas.toBlob(
15208
+ (blob2) => {
15209
+ if (blob2) {
15210
+ resolve(blob2);
15211
+ } else {
15212
+ reject(new Error("JPG \u5BFC\u51FA\u5931\u8D25"));
15213
+ }
15214
+ },
15215
+ "image/jpeg",
15216
+ quality
15217
+ );
15218
+ };
15219
+ img.onerror = () => {
15220
+ URL.revokeObjectURL(url);
15221
+ reject(new Error("SVG \u56FE\u50CF\u52A0\u8F7D\u5931\u8D25"));
15222
+ };
15223
+ img.src = url;
15224
+ });
15225
+ }
15226
+ async function exportMP4(svg, captureFrame, options = {}) {
15227
+ const { fps = 60, duration = 3 } = options;
15228
+ if (typeof VideoEncoder === "undefined") {
15229
+ throw new Error("\u6D4F\u89C8\u5668\u4E0D\u652F\u6301 VideoEncoder API");
15230
+ }
15231
+ const { Muxer, ArrayBufferTarget } = await import("mp4-muxer");
15232
+ const width = svg.clientWidth || 800;
15233
+ const height = svg.clientHeight || 450;
15234
+ const encoderWidth = Math.ceil(width / 2) * 2;
15235
+ const encoderHeight = Math.ceil(height / 2) * 2;
15236
+ const target = new ArrayBufferTarget();
15237
+ const muxer = new Muxer({
15238
+ target,
15239
+ video: {
15240
+ codec: "avc",
15241
+ width: encoderWidth,
15242
+ height: encoderHeight
15243
+ },
15244
+ fastStart: "in-memory"
15245
+ });
15246
+ const encoder = new VideoEncoder({
15247
+ output: (chunk, meta) => {
15248
+ muxer.addVideoChunk(chunk, meta);
15249
+ },
15250
+ error: (e) => {
15251
+ console.error("VideoEncoder error:", e);
15252
+ }
15253
+ });
15254
+ encoder.configure({
15255
+ codec: "avc1.42001f",
15256
+ width: encoderWidth,
15257
+ height: encoderHeight,
15258
+ bitrate: 5e6,
15259
+ framerate: fps
15260
+ });
15261
+ const canvas = document.createElement("canvas");
15262
+ canvas.width = encoderWidth;
15263
+ canvas.height = encoderHeight;
15264
+ const ctx = canvas.getContext("2d");
15265
+ if (!ctx) {
15266
+ throw new Error("\u65E0\u6CD5\u521B\u5EFA Canvas \u4E0A\u4E0B\u6587");
15267
+ }
15268
+ const totalFrames = Math.ceil(duration * fps);
15269
+ const frameDuration = 1e6 / fps;
15270
+ for (let i = 0; i < totalFrames; i++) {
15271
+ await captureFrame();
15272
+ const svgString = new XMLSerializer().serializeToString(svg);
15273
+ const blob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
15274
+ const url = URL.createObjectURL(blob);
15275
+ await new Promise((resolve, reject) => {
15276
+ const img = new Image();
15277
+ img.onload = () => {
15278
+ ctx.fillStyle = "#000000";
15279
+ ctx.fillRect(0, 0, encoderWidth, encoderHeight);
15280
+ ctx.drawImage(img, 0, 0, encoderWidth, encoderHeight);
15281
+ URL.revokeObjectURL(url);
15282
+ resolve();
15283
+ };
15284
+ img.onerror = () => {
15285
+ URL.revokeObjectURL(url);
15286
+ reject(new Error("\u5E27\u6355\u83B7\u5931\u8D25"));
15287
+ };
15288
+ img.src = url;
15289
+ });
15290
+ const frame = new VideoFrame(canvas, {
15291
+ timestamp: i * frameDuration,
15292
+ duration: frameDuration
15293
+ });
15294
+ encoder.encode(frame);
15295
+ frame.close();
15296
+ }
15297
+ await encoder.flush();
15298
+ encoder.close();
15299
+ muxer.finalize();
15300
+ const buffer = target.buffer;
15301
+ return new Blob([buffer], { type: "video/mp4" });
15302
+ }
15303
+ function downloadFile(blob, filename) {
15304
+ const url = typeof blob === "string" ? `data:image/svg+xml;charset=utf-8,${encodeURIComponent(blob)}` : URL.createObjectURL(blob);
15305
+ const a = document.createElement("a");
15306
+ a.href = url;
15307
+ a.download = filename;
15308
+ document.body.appendChild(a);
15309
+ a.click();
15310
+ document.body.removeChild(a);
15311
+ if (typeof blob !== "string") {
15312
+ URL.revokeObjectURL(url);
15313
+ }
15314
+ }
15315
+
15316
+ // src/showcase/ShowcaseCore.ts
15317
+ function createShowcase(options) {
15318
+ let status = "idle";
15319
+ let mode = null;
15320
+ let animationState = "idle";
15321
+ let error = null;
15322
+ let container = null;
15323
+ let svg = null;
15324
+ let sceneInstance = null;
15325
+ let interactiveInstance = null;
15326
+ let diagrams = [];
15327
+ const {
15328
+ code: code2,
15329
+ diagram,
15330
+ sceneClass,
15331
+ width: configWidth = "auto",
15332
+ height: configHeight = "auto",
15333
+ aspectRatio = 16 / 9,
15334
+ background = "#000",
15335
+ onReady,
15336
+ onError,
15337
+ onStatusChange
15338
+ } = options;
15339
+ function setStatus(newStatus) {
15340
+ status = newStatus;
15341
+ onStatusChange == null ? void 0 : onStatusChange(newStatus);
15342
+ }
15343
+ function getDimensions() {
15344
+ if (!container) return { width: 800, height: 450 };
15345
+ const containerWidth = container.clientWidth || 800;
15346
+ const width = configWidth === "auto" ? containerWidth : configWidth;
15347
+ const height = configHeight === "auto" ? Math.round(width / aspectRatio) : configHeight;
15348
+ return { width, height };
15349
+ }
15350
+ function createSVG() {
15351
+ const { width, height } = getDimensions();
15352
+ const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
15353
+ svgElement.setAttribute("width", String(width));
15354
+ svgElement.setAttribute("height", String(height));
15355
+ svgElement.style.width = "100%";
15356
+ svgElement.style.aspectRatio = String(aspectRatio);
15357
+ svgElement.style.borderRadius = "8px";
15358
+ svgElement.style.overflow = "hidden";
15359
+ svgElement.style.background = background;
15360
+ return svgElement;
15361
+ }
15362
+ function cleanup() {
15363
+ if (sceneInstance) {
15364
+ if ("destroy" in sceneInstance && typeof sceneInstance.destroy === "function") {
15365
+ sceneInstance.destroy();
15366
+ }
15367
+ sceneInstance = null;
15368
+ }
15369
+ if (interactiveInstance) {
15370
+ if (typeof interactiveInstance.destroy === "function") {
15371
+ interactiveInstance.destroy();
15372
+ }
15373
+ interactiveInstance = null;
15374
+ }
15375
+ if (svg && svg.parentElement) {
15376
+ svg.remove();
15377
+ }
15378
+ svg = null;
15379
+ diagrams = [];
15380
+ mode = null;
15381
+ animationState = "idle";
15382
+ }
15383
+ function renderStatic() {
15384
+ if (!svg || diagrams.length === 0) return;
15385
+ const { width, height } = getDimensions();
15386
+ const combined = diagrams.length === 1 ? diagrams[0] : combine(...diagrams);
15387
+ renderToSVG(combined, svg, {
15388
+ width,
15389
+ height,
15390
+ background
15391
+ });
15392
+ const bounds = combined.bounds();
15393
+ if (bounds.width > 0 && bounds.height > 0) {
15394
+ const padding = 0.5;
15395
+ const contentW = bounds.width + padding * 2;
15396
+ const contentH = bounds.height + padding * 2;
15397
+ const vX = bounds.x - padding;
15398
+ const vY = bounds.y - padding;
15399
+ svg.setAttribute("viewBox", `${vX} ${vY} ${contentW} ${contentH}`);
15400
+ }
15401
+ svg.removeAttribute("width");
15402
+ svg.removeAttribute("height");
15403
+ svg.style.overflow = "visible";
15404
+ }
15405
+ const controller = {
15406
+ get status() {
15407
+ return status;
15408
+ },
15409
+ get mode() {
15410
+ return mode;
15411
+ },
15412
+ get animationState() {
15413
+ return animationState;
15414
+ },
15415
+ get error() {
15416
+ return error;
15417
+ },
15418
+ /**
15419
+ * 初始化
15420
+ */
15421
+ async init(containerElement) {
15422
+ container = containerElement;
15423
+ setStatus("loading");
15424
+ error = null;
15425
+ try {
15426
+ cleanup();
15427
+ svg = createSVG();
15428
+ container.appendChild(svg);
15429
+ const { width, height } = getDimensions();
15430
+ if (diagram) {
15431
+ mode = "static";
15432
+ diagrams = [diagram];
15433
+ renderStatic();
15434
+ } else if (sceneClass) {
15435
+ mode = "animation";
15436
+ const newScene = new sceneClass();
15437
+ newScene.setup(svg, { width, height, background });
15438
+ await newScene.construct();
15439
+ sceneInstance = newScene;
15440
+ } else if (code2) {
15441
+ mode = detectRenderMode(code2);
15442
+ const result = await executeCode(code2, svg, { width, height, background });
15443
+ diagrams = result.diagrams;
15444
+ sceneInstance = result.scene;
15445
+ interactiveInstance = result.interactive;
15446
+ if (result.mode === "static" && diagrams.length > 0) {
15447
+ renderStatic();
15448
+ }
15449
+ } else {
15450
+ throw new Error("\u5FC5\u987B\u63D0\u4F9B code\u3001diagram \u6216 sceneClass \u4E4B\u4E00");
15451
+ }
15452
+ setStatus("ready");
15453
+ onReady == null ? void 0 : onReady();
15454
+ } catch (e) {
15455
+ error = e;
15456
+ setStatus("error");
15457
+ onError == null ? void 0 : onError(error);
15458
+ console.error("Showcase \u521D\u59CB\u5316\u9519\u8BEF:", error);
15459
+ }
15460
+ },
15461
+ /**
15462
+ * 销毁
15463
+ */
15464
+ destroy() {
15465
+ cleanup();
15466
+ container = null;
15467
+ setStatus("idle");
15468
+ },
15469
+ /**
15470
+ * 重置
15471
+ */
15472
+ async reset() {
15473
+ if (container) {
15474
+ await controller.init(container);
15475
+ }
15476
+ },
15477
+ /**
15478
+ * 播放动画
15479
+ */
15480
+ play() {
15481
+ if (mode !== "animation" || !sceneInstance) return;
15482
+ if (animationState === "idle") {
15483
+ sceneInstance.start();
15484
+ animationState = "playing";
15485
+ } else if (animationState === "paused") {
15486
+ sceneInstance.resume();
15487
+ animationState = "playing";
15488
+ }
15489
+ },
15490
+ /**
15491
+ * 暂停动画
15492
+ */
15493
+ pause() {
15494
+ if (mode !== "animation" || !sceneInstance) return;
15495
+ if (animationState === "playing") {
15496
+ sceneInstance.pause();
15497
+ animationState = "paused";
15498
+ }
15499
+ },
15500
+ /**
15501
+ * 恢复动画
15502
+ */
15503
+ resume() {
15504
+ if (mode !== "animation" || !sceneInstance) return;
15505
+ if (animationState === "paused") {
15506
+ sceneInstance.resume();
15507
+ animationState = "playing";
15508
+ }
15509
+ },
15510
+ /**
15511
+ * 导出 SVG
15512
+ */
15513
+ async exportSVG() {
15514
+ if (!svg) throw new Error("SVG \u672A\u521D\u59CB\u5316");
15515
+ return exportSVG(svg);
15516
+ },
15517
+ /**
15518
+ * 导出 JPG
15519
+ */
15520
+ async exportJPG(quality = 0.9) {
15521
+ if (!svg) throw new Error("SVG \u672A\u521D\u59CB\u5316");
15522
+ const { width, height } = getDimensions();
15523
+ return exportJPG(svg, { quality, width, height });
15524
+ },
15525
+ /**
15526
+ * 导出 MP4
15527
+ */
15528
+ async exportMP4(exportOptions = {}) {
15529
+ if (!svg) throw new Error("SVG \u672A\u521D\u59CB\u5316");
15530
+ if (mode !== "animation" || !sceneInstance) {
15531
+ throw new Error("\u53EA\u6709\u52A8\u753B\u6A21\u5F0F\u652F\u6301 MP4 \u5BFC\u51FA");
15532
+ }
15533
+ await controller.reset();
15534
+ const captureFrame = async () => {
15535
+ await new Promise((resolve) => setTimeout(resolve, 16));
15536
+ };
15537
+ return exportMP4(svg, captureFrame, exportOptions);
15538
+ }
15539
+ };
15540
+ return controller;
15541
+ }
15542
+
15543
+ // src/showcase/hooks/useShowcase.ts
15544
+ function useShowcase(options) {
15545
+ const containerRef = useRef(null);
15546
+ const controllerRef = useRef(null);
15547
+ const [status, setStatus] = useState("idle");
15548
+ const [mode, setMode] = useState(null);
15549
+ const [animationState, setAnimationState] = useState("idle");
15550
+ const [error, setError] = useState(null);
15551
+ useEffect(() => {
15552
+ if (!containerRef.current) return;
15553
+ const controller = createShowcase(__spreadProps(__spreadValues({}, options), {
15554
+ onStatusChange: (newStatus) => {
15555
+ var _a;
15556
+ setStatus(newStatus);
15557
+ (_a = options.onStatusChange) == null ? void 0 : _a.call(options, newStatus);
15558
+ },
15559
+ onReady: () => {
15560
+ var _a;
15561
+ setMode(controller.mode);
15562
+ setAnimationState(controller.animationState);
15563
+ (_a = options.onReady) == null ? void 0 : _a.call(options);
15564
+ },
15565
+ onError: (err) => {
15566
+ var _a;
15567
+ setError(err);
15568
+ (_a = options.onError) == null ? void 0 : _a.call(options, err);
15569
+ }
15570
+ }));
15571
+ controllerRef.current = controller;
15572
+ controller.init(containerRef.current);
15573
+ return () => {
15574
+ controller.destroy();
15575
+ controllerRef.current = null;
15576
+ };
15577
+ }, [options.code, options.diagram, options.sceneClass]);
15578
+ const play = useCallback(() => {
15579
+ if (controllerRef.current) {
15580
+ controllerRef.current.play();
15581
+ setAnimationState("playing");
15582
+ }
15583
+ }, []);
15584
+ const pause = useCallback(() => {
15585
+ if (controllerRef.current) {
15586
+ controllerRef.current.pause();
15587
+ setAnimationState("paused");
15588
+ }
15589
+ }, []);
15590
+ const resume = useCallback(() => {
15591
+ if (controllerRef.current) {
15592
+ controllerRef.current.resume();
15593
+ setAnimationState("playing");
15594
+ }
15595
+ }, []);
15596
+ const reset = useCallback(async () => {
15597
+ if (controllerRef.current) {
15598
+ await controllerRef.current.reset();
15599
+ setAnimationState("idle");
15600
+ }
15601
+ }, []);
15602
+ const exportSVG2 = useCallback(async () => {
15603
+ if (!controllerRef.current) {
15604
+ throw new Error("Showcase \u672A\u521D\u59CB\u5316");
15605
+ }
15606
+ return controllerRef.current.exportSVG();
15607
+ }, []);
15608
+ const exportJPG2 = useCallback(async (quality) => {
15609
+ if (!controllerRef.current) {
15610
+ throw new Error("Showcase \u672A\u521D\u59CB\u5316");
15611
+ }
15612
+ return controllerRef.current.exportJPG(quality);
15613
+ }, []);
15614
+ const exportMP42 = useCallback(async (exportOptions) => {
15615
+ if (!controllerRef.current) {
15616
+ throw new Error("Showcase \u672A\u521D\u59CB\u5316");
15617
+ }
15618
+ return controllerRef.current.exportMP4(exportOptions);
15619
+ }, []);
15620
+ return {
15621
+ containerRef,
15622
+ status,
15623
+ mode,
15624
+ animationState,
15625
+ error,
15626
+ play,
15627
+ pause,
15628
+ resume,
15629
+ reset,
15630
+ exportSVG: exportSVG2,
15631
+ exportJPG: exportJPG2,
15632
+ exportMP4: exportMP42
15633
+ };
15634
+ }
15635
+
15636
+ // src/showcase/hooks/useExport.ts
15637
+ import { useCallback as useCallback2, useState as useState2 } from "react";
15638
+ function useExport() {
15639
+ const [status, setStatus] = useState2("idle");
15640
+ const [error, setError] = useState2(null);
15641
+ const downloadSVG = useCallback2(async (getSVG, filename = "diagram.svg") => {
15642
+ setStatus("exporting");
15643
+ setError(null);
15644
+ try {
15645
+ const svgString = await getSVG();
15646
+ downloadFile(svgString, filename);
15647
+ setStatus("success");
15648
+ } catch (err) {
15649
+ setError(err);
15650
+ setStatus("error");
15651
+ throw err;
15652
+ }
15653
+ }, []);
15654
+ const downloadJPG = useCallback2(async (getJPG, filename = "diagram.jpg") => {
15655
+ setStatus("exporting");
15656
+ setError(null);
15657
+ try {
15658
+ const blob = await getJPG();
15659
+ downloadFile(blob, filename);
15660
+ setStatus("success");
15661
+ } catch (err) {
15662
+ setError(err);
15663
+ setStatus("error");
15664
+ throw err;
15665
+ }
15666
+ }, []);
15667
+ const downloadMP4 = useCallback2(async (getMP4, filename = "animation.mp4") => {
15668
+ setStatus("exporting");
15669
+ setError(null);
15670
+ try {
15671
+ const blob = await getMP4();
15672
+ downloadFile(blob, filename);
15673
+ setStatus("success");
15674
+ } catch (err) {
15675
+ setError(err);
15676
+ setStatus("error");
15677
+ throw err;
15678
+ }
15679
+ }, []);
15680
+ return {
15681
+ status,
15682
+ error,
15683
+ downloadSVG,
15684
+ downloadJPG,
15685
+ downloadMP4
15686
+ };
15687
+ }
15688
+
15689
+ // src/showcase/Showcase.tsx
15690
+ function Showcase({
15691
+ code: code2,
15692
+ diagram,
15693
+ sceneClass,
15694
+ width = "auto",
15695
+ height = "auto",
15696
+ aspectRatio = 16 / 9,
15697
+ background = "#000",
15698
+ className,
15699
+ showControls = true,
15700
+ showExport = true,
15701
+ showCode = false,
15702
+ onReady,
15703
+ onError,
15704
+ onStatusChange
15705
+ }) {
15706
+ const showcaseOptions = {
15707
+ width,
15708
+ height,
15709
+ aspectRatio,
15710
+ background
15711
+ };
15712
+ if (code2 !== void 0) showcaseOptions.code = code2;
15713
+ if (diagram !== void 0) showcaseOptions.diagram = diagram;
15714
+ if (sceneClass !== void 0) showcaseOptions.sceneClass = sceneClass;
15715
+ if (onReady !== void 0) showcaseOptions.onReady = onReady;
15716
+ if (onError !== void 0) showcaseOptions.onError = onError;
15717
+ if (onStatusChange !== void 0) showcaseOptions.onStatusChange = onStatusChange;
15718
+ const {
15719
+ containerRef,
15720
+ status,
15721
+ mode,
15722
+ animationState,
15723
+ error,
15724
+ play,
15725
+ pause,
15726
+ reset,
15727
+ exportSVG: exportSVG2,
15728
+ exportJPG: exportJPG2,
15729
+ exportMP4: exportMP42
15730
+ } = useShowcase(showcaseOptions);
15731
+ const {
15732
+ status: exportStatus,
15733
+ downloadSVG,
15734
+ downloadJPG,
15735
+ downloadMP4
15736
+ } = useExport();
15737
+ const shouldShowControls = showControls && mode === "animation";
15738
+ const shouldShowExport = showExport && status === "ready";
15739
+ const handlePlayPause = useCallback3(() => {
15740
+ if (animationState === "playing") {
15741
+ pause();
15742
+ } else {
15743
+ play();
15744
+ }
15745
+ }, [animationState, play, pause]);
15746
+ const handleExportSVG = useCallback3(() => {
15747
+ downloadSVG(exportSVG2, "locusing-diagram.svg");
15748
+ }, [downloadSVG, exportSVG2]);
15749
+ const handleExportJPG = useCallback3(() => {
15750
+ downloadJPG(() => exportJPG2(0.9), "locusing-diagram.jpg");
15751
+ }, [downloadJPG, exportJPG2]);
15752
+ const handleExportMP4 = useCallback3(() => {
15753
+ downloadMP4(exportMP42, "locusing-animation.mp4");
15754
+ }, [downloadMP4, exportMP42]);
15755
+ const containerStyle = useMemo(() => ({
15756
+ position: "relative",
15757
+ width: width === "auto" ? "100%" : width,
15758
+ aspectRatio: height === "auto" ? String(aspectRatio) : void 0,
15759
+ height: height === "auto" ? void 0 : height,
15760
+ borderRadius: "8px",
15761
+ overflow: "hidden",
15762
+ background
15763
+ }), [width, height, aspectRatio, background]);
15764
+ const controlsStyle = useMemo(() => ({
15765
+ position: "absolute",
15766
+ bottom: "12px",
15767
+ left: "50%",
15768
+ transform: "translateX(-50%)",
15769
+ display: "flex",
15770
+ gap: "8px",
15771
+ padding: "8px 12px",
15772
+ background: "rgba(0, 0, 0, 0.6)",
15773
+ borderRadius: "8px",
15774
+ backdropFilter: "blur(4px)"
15775
+ }), []);
15776
+ const buttonStyle = useMemo(() => ({
15777
+ padding: "6px 12px",
15778
+ border: "none",
15779
+ borderRadius: "4px",
15780
+ background: "rgba(255, 255, 255, 0.2)",
15781
+ color: "#fff",
15782
+ cursor: "pointer",
15783
+ fontSize: "14px",
15784
+ transition: "background 0.2s"
15785
+ }), []);
15786
+ if (status === "loading") {
15787
+ return /* @__PURE__ */ React.createElement("div", { className, style: containerStyle }, /* @__PURE__ */ React.createElement("div", { style: {
15788
+ display: "flex",
15789
+ alignItems: "center",
15790
+ justifyContent: "center",
15791
+ width: "100%",
15792
+ height: "100%",
15793
+ color: "rgba(255, 255, 255, 0.6)"
15794
+ } }, "\u52A0\u8F7D\u4E2D..."));
15795
+ }
15796
+ if (status === "error" && error) {
15797
+ return /* @__PURE__ */ React.createElement("div", { className, style: containerStyle }, /* @__PURE__ */ React.createElement("div", { style: {
15798
+ display: "flex",
15799
+ flexDirection: "column",
15800
+ alignItems: "center",
15801
+ justifyContent: "center",
15802
+ width: "100%",
15803
+ height: "100%",
15804
+ color: "#ff6b6b",
15805
+ padding: "20px",
15806
+ textAlign: "center"
15807
+ } }, /* @__PURE__ */ React.createElement("div", { style: { marginBottom: "8px" } }, "\u6E32\u67D3\u9519\u8BEF"), /* @__PURE__ */ React.createElement("div", { style: { fontSize: "12px", opacity: 0.8 } }, error.message)));
15808
+ }
15809
+ return /* @__PURE__ */ React.createElement("div", { className, style: containerStyle }, /* @__PURE__ */ React.createElement(
15810
+ "div",
15811
+ {
15812
+ ref: containerRef,
15813
+ style: {
15814
+ width: "100%",
15815
+ height: "100%"
15816
+ }
15817
+ }
15818
+ ), shouldShowControls && /* @__PURE__ */ React.createElement("div", { style: controlsStyle }, /* @__PURE__ */ React.createElement(
15819
+ "button",
15820
+ {
15821
+ style: buttonStyle,
15822
+ onClick: handlePlayPause,
15823
+ onMouseOver: (e) => e.currentTarget.style.background = "rgba(255, 255, 255, 0.3)",
15824
+ onMouseOut: (e) => e.currentTarget.style.background = "rgba(255, 255, 255, 0.2)"
15825
+ },
15826
+ animationState === "playing" ? "\u6682\u505C" : "\u64AD\u653E"
15827
+ ), /* @__PURE__ */ React.createElement(
15828
+ "button",
15829
+ {
15830
+ style: buttonStyle,
15831
+ onClick: reset,
15832
+ onMouseOver: (e) => e.currentTarget.style.background = "rgba(255, 255, 255, 0.3)",
15833
+ onMouseOut: (e) => e.currentTarget.style.background = "rgba(255, 255, 255, 0.2)"
15834
+ },
15835
+ "\u91CD\u7F6E"
15836
+ )), shouldShowExport && /* @__PURE__ */ React.createElement("div", { style: {
15837
+ position: "absolute",
15838
+ top: "12px",
15839
+ right: "12px",
15840
+ display: "flex",
15841
+ gap: "4px"
15842
+ } }, /* @__PURE__ */ React.createElement(
15843
+ "button",
15844
+ {
15845
+ style: __spreadProps(__spreadValues({}, buttonStyle), {
15846
+ padding: "4px 8px",
15847
+ fontSize: "12px"
15848
+ }),
15849
+ onClick: handleExportSVG,
15850
+ disabled: exportStatus === "exporting",
15851
+ onMouseOver: (e) => e.currentTarget.style.background = "rgba(255, 255, 255, 0.3)",
15852
+ onMouseOut: (e) => e.currentTarget.style.background = "rgba(255, 255, 255, 0.2)"
15853
+ },
15854
+ "SVG"
15855
+ ), /* @__PURE__ */ React.createElement(
15856
+ "button",
15857
+ {
15858
+ style: __spreadProps(__spreadValues({}, buttonStyle), {
15859
+ padding: "4px 8px",
15860
+ fontSize: "12px"
15861
+ }),
15862
+ onClick: handleExportJPG,
15863
+ disabled: exportStatus === "exporting",
15864
+ onMouseOver: (e) => e.currentTarget.style.background = "rgba(255, 255, 255, 0.3)",
15865
+ onMouseOut: (e) => e.currentTarget.style.background = "rgba(255, 255, 255, 0.2)"
15866
+ },
15867
+ "JPG"
15868
+ ), mode === "animation" && /* @__PURE__ */ React.createElement(
15869
+ "button",
15870
+ {
15871
+ style: __spreadProps(__spreadValues({}, buttonStyle), {
15872
+ padding: "4px 8px",
15873
+ fontSize: "12px"
15874
+ }),
15875
+ onClick: handleExportMP4,
15876
+ disabled: exportStatus === "exporting",
15877
+ onMouseOver: (e) => e.currentTarget.style.background = "rgba(255, 255, 255, 0.3)",
15878
+ onMouseOut: (e) => e.currentTarget.style.background = "rgba(255, 255, 255, 0.2)"
15879
+ },
15880
+ "MP4"
15881
+ )), showCode && code2 && /* @__PURE__ */ React.createElement("details", { style: {
15882
+ position: "absolute",
15883
+ bottom: shouldShowControls ? "60px" : "12px",
15884
+ left: "12px",
15885
+ right: "12px",
15886
+ background: "rgba(0, 0, 0, 0.8)",
15887
+ borderRadius: "8px",
15888
+ padding: "8px 12px",
15889
+ color: "#fff",
15890
+ fontSize: "12px",
15891
+ maxHeight: "200px",
15892
+ overflow: "auto"
15893
+ } }, /* @__PURE__ */ React.createElement("summary", { style: { cursor: "pointer", marginBottom: "8px" } }, "\u67E5\u770B\u4EE3\u7801"), /* @__PURE__ */ React.createElement("pre", { style: { margin: 0, whiteSpace: "pre-wrap" } }, code2)));
15894
+ }
13978
15895
  export {
13979
15896
  AddTextLetterByLetter,
13980
15897
  AddTextWordByWord,
@@ -14063,6 +15980,7 @@ export {
14063
15980
  Shift,
14064
15981
  ShowIncreasingSubsets,
14065
15982
  ShowPassingFlash,
15983
+ Showcase,
14066
15984
  ShrinkToCenter,
14067
15985
  SpinInFromNothing,
14068
15986
  SpiralIn,
@@ -14164,6 +16082,7 @@ export {
14164
16082
  createPhysicsWorld,
14165
16083
  createPlane,
14166
16084
  createScene,
16085
+ createShowcase,
14167
16086
  createSphere,
14168
16087
  createSpringMass,
14169
16088
  createTheme,
@@ -14209,6 +16128,7 @@ export {
14209
16128
  defaultTheme,
14210
16129
  defaultTokens,
14211
16130
  degToRad,
16131
+ detectRenderMode,
14212
16132
  determinant,
14213
16133
  diagram_combine,
14214
16134
  diff,
@@ -14219,6 +16139,7 @@ export {
14219
16139
  dot2 as dot,
14220
16140
  dot3D,
14221
16141
  doubleArrow,
16142
+ downloadFile,
14222
16143
  draw_to_svg,
14223
16144
  draw_to_svg_string,
14224
16145
  easing,
@@ -14227,6 +16148,7 @@ export {
14227
16148
  ellipse,
14228
16149
  empty,
14229
16150
  equilateralTriangle,
16151
+ executeCode,
14230
16152
  footOfPerpendicular,
14231
16153
  functionConstraint,
14232
16154
  getBuffer,
@@ -14296,6 +16218,7 @@ export {
14296
16218
  polygon,
14297
16219
  polyline,
14298
16220
  powScale,
16221
+ preprocessCode,
14299
16222
  quadraticBezier,
14300
16223
  radToDeg,
14301
16224
  randomLayout,
@@ -14322,6 +16245,9 @@ export {
14322
16245
  sector,
14323
16246
  semanticStyle,
14324
16247
  setCurrentTheme,
16248
+ exportJPG as showcaseExportJPG,
16249
+ exportMP4 as showcaseExportMP4,
16250
+ exportSVG as showcaseExportSVG,
14325
16251
  shuffle2 as shuffle,
14326
16252
  sortGroups,
14327
16253
  sphere,
@@ -14344,6 +16270,8 @@ export {
14344
16270
  translationMatrix,
14345
16271
  treeLayout,
14346
16272
  triangle,
16273
+ useExport,
16274
+ useShowcase,
14347
16275
  vector,
14348
16276
  vector3D,
14349
16277
  dot as vectorDot