locusing 0.1.2

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.
@@ -0,0 +1,1945 @@
1
+ /**
2
+ * @locusing/math - 数学工具库
3
+ *
4
+ * 提供向量、矩阵、贝塞尔曲线等数学运算
5
+ */
6
+ type Vector2 = [number, number];
7
+ type Vector3 = [number, number, number];
8
+ type Point = Vector2;
9
+ declare function V2(x: number, y: number): Vector2;
10
+ declare function V3(x: number, y: number, z: number): Vector3;
11
+ declare const ORIGIN: Vector2;
12
+ declare const UP: Vector2;
13
+ declare const DOWN: Vector2;
14
+ declare const LEFT: Vector2;
15
+ declare const RIGHT: Vector2;
16
+ declare const UL: Vector2;
17
+ declare const UR: Vector2;
18
+ declare const DL: Vector2;
19
+ declare const DR: Vector2;
20
+ /**
21
+ * Manim 风格方向常量(数学坐标系,Y 向上为正)
22
+ *
23
+ * 用于 Frame 模式渲染,原点在画布中心
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * import { Dir, scale } from 'locusing';
28
+ *
29
+ * // 正方形向上移动 2 单位
30
+ * square(1).move(scale(Dir.UP, 2));
31
+ *
32
+ * // 圆形在右下角
33
+ * circle(0.5).move(scale(Dir.DR, 3));
34
+ * ```
35
+ */
36
+ declare const Dir: {
37
+ /** 原点 [0, 0] */
38
+ ORIGIN: Vector2;
39
+ /** 向上 [0, 1] */
40
+ UP: Vector2;
41
+ /** 向下 [0, -1] */
42
+ DOWN: Vector2;
43
+ /** 向左 [-1, 0] */
44
+ LEFT: Vector2;
45
+ /** 向右 [1, 0] */
46
+ RIGHT: Vector2;
47
+ /** 左上 [-1, 1] */
48
+ UL: Vector2;
49
+ /** 右上 [1, 1] */
50
+ UR: Vector2;
51
+ /** 左下 [-1, -1] */
52
+ DL: Vector2;
53
+ /** 右下 [1, -1] */
54
+ DR: Vector2;
55
+ };
56
+ declare function add(a: Vector2, b: Vector2): Vector2;
57
+ declare function sub(a: Vector2, b: Vector2): Vector2;
58
+ declare function mul(v: Vector2, scalar: number): Vector2;
59
+ declare function div(v: Vector2, scalar: number): Vector2;
60
+ declare function dot(a: Vector2, b: Vector2): number;
61
+ declare function cross(a: Vector2, b: Vector2): number;
62
+ declare function length(v: Vector2): number;
63
+ declare function normalize(v: Vector2): Vector2;
64
+ declare function distance(a: Vector2, b: Vector2): number;
65
+ declare function angle(v: Vector2): number;
66
+ declare function angleBetween(a: Vector2, b: Vector2): number;
67
+ declare function rotate(v: Vector2, radians: number): Vector2;
68
+ declare function lerp(a: Vector2, b: Vector2, t: number): Vector2;
69
+ declare function midpoint(a: Vector2, b: Vector2): Vector2;
70
+ declare function perpendicular(v: Vector2): Vector2;
71
+ declare function reflect(v: Vector2, normal: Vector2): Vector2;
72
+ type Matrix3 = [
73
+ number,
74
+ number,
75
+ number,
76
+ number,
77
+ number,
78
+ number,
79
+ number,
80
+ number,
81
+ number
82
+ ];
83
+ declare const IDENTITY: Matrix3;
84
+ declare function matrixMultiply(a: Matrix3, b: Matrix3): Matrix3;
85
+ declare function applyMatrix(m: Matrix3, v: Vector2): Vector2;
86
+ declare function translationMatrix(tx: number, ty: number): Matrix3;
87
+ declare function rotationMatrix(radians: number): Matrix3;
88
+ declare function scaleMatrix(sx: number, sy?: number): Matrix3;
89
+ declare function quadraticBezier(p0: Vector2, p1: Vector2, p2: Vector2, t: number): Vector2;
90
+ declare function cubicBezier(p0: Vector2, p1: Vector2, p2: Vector2, p3: Vector2, t: number): Vector2;
91
+ declare function sampleParametric(fn: (t: number) => Vector2, start?: number, end?: number, segments?: number): Vector2[];
92
+ type EasingFunction = (t: number) => number;
93
+ declare const easing: {
94
+ linear: (t: number) => number;
95
+ easeInQuad: (t: number) => number;
96
+ easeOutQuad: (t: number) => number;
97
+ easeInOutQuad: (t: number) => number;
98
+ easeInCubic: (t: number) => number;
99
+ easeOutCubic: (t: number) => number;
100
+ easeInOutCubic: (t: number) => number;
101
+ easeInSine: (t: number) => number;
102
+ easeOutSine: (t: number) => number;
103
+ easeInOutSine: (t: number) => number;
104
+ easeInExpo: (t: number) => number;
105
+ easeOutExpo: (t: number) => number;
106
+ easeInOutExpo: (t: number) => number;
107
+ easeInBack: (t: number) => number;
108
+ easeOutBack: (t: number) => number;
109
+ easeInOutBack: (t: number) => number;
110
+ easeInElastic: (t: number) => number;
111
+ easeOutElastic: (t: number) => number;
112
+ easeInBounce: (t: number) => number;
113
+ easeOutBounce: (t: number) => number;
114
+ /**
115
+ * thereAndBack - 去而复返
116
+ *
117
+ * 从 0 开始,到 0.5 时达到 1,然后回到 0
118
+ */
119
+ thereAndBack: (t: number) => number;
120
+ /**
121
+ * thereAndBackWithPause - 去而复返(带停顿)
122
+ *
123
+ * 类似 thereAndBack,但在中间有一段停留时间
124
+ * @param pauseRatio - 停顿占总时间的比例,默认 1/3
125
+ */
126
+ thereAndBackWithPause: (t: number, pauseRatio?: number) => number;
127
+ /**
128
+ * runningStart - 起跑式
129
+ *
130
+ * 先后退一点,再向前冲(类似起跑动作)
131
+ * @param pullFactor - 后退程度,默认 -0.3
132
+ */
133
+ runningStart: (t: number, pullFactor?: number) => number;
134
+ /**
135
+ * wiggle - 摇摆
136
+ *
137
+ * 产生摇摆效果,适合强调动画
138
+ */
139
+ wiggle: (t: number, wiggles?: number) => number;
140
+ /**
141
+ * exponentialDecay - 指数衰减
142
+ *
143
+ * 快速到达目标后缓慢稳定
144
+ * @param halfLife - 半衰期,值越小衰减越快,默认 0.1
145
+ */
146
+ exponentialDecay: (t: number, halfLife?: number) => number;
147
+ };
148
+ declare const PI: number;
149
+ declare const TAU: number;
150
+ declare const DEGREES: number;
151
+ declare function degToRad(degrees: number): number;
152
+ declare function radToDeg(radians: number): number;
153
+ declare function clamp(value: number, min: number, max: number): number;
154
+ declare function mapRange(value: number, inMin: number, inMax: number, outMin: number, outMax: number): number;
155
+ declare function lerpNumber(a: number, b: number, t: number): number;
156
+
157
+ /**
158
+ * @locusing/core - 核心类型定义
159
+ */
160
+
161
+ interface Style {
162
+ fill?: string;
163
+ fillOpacity?: number;
164
+ stroke?: string;
165
+ strokeWidth?: number;
166
+ strokeOpacity?: number;
167
+ strokeDasharray?: string;
168
+ strokeLinecap?: 'butt' | 'round' | 'square';
169
+ strokeLinejoin?: 'miter' | 'round' | 'bevel';
170
+ opacity?: number;
171
+ }
172
+ interface TextStyle extends Style {
173
+ fontSize?: number;
174
+ fontFamily?: string;
175
+ fontWeight?: string | number;
176
+ fontStyle?: string;
177
+ textAnchor?: 'start' | 'middle' | 'end';
178
+ dominantBaseline?: 'auto' | 'middle' | 'hanging' | 'central';
179
+ }
180
+ type ShapeType = 'group' | 'path' | 'rect' | 'circle' | 'ellipse' | 'line' | 'polyline' | 'polygon' | 'text' | 'arc' | 'tex' | 'svg' | 'image';
181
+ type PathCommand = {
182
+ type: 'M';
183
+ x: number;
184
+ y: number;
185
+ } | {
186
+ type: 'L';
187
+ x: number;
188
+ y: number;
189
+ } | {
190
+ type: 'H';
191
+ x: number;
192
+ } | {
193
+ type: 'V';
194
+ y: number;
195
+ } | {
196
+ type: 'C';
197
+ x1: number;
198
+ y1: number;
199
+ x2: number;
200
+ y2: number;
201
+ x: number;
202
+ y: number;
203
+ } | {
204
+ type: 'S';
205
+ x2: number;
206
+ y2: number;
207
+ x: number;
208
+ y: number;
209
+ } | {
210
+ type: 'Q';
211
+ x1: number;
212
+ y1: number;
213
+ x: number;
214
+ y: number;
215
+ } | {
216
+ type: 'T';
217
+ x: number;
218
+ y: number;
219
+ } | {
220
+ type: 'A';
221
+ rx: number;
222
+ ry: number;
223
+ angle: number;
224
+ largeArc: boolean;
225
+ sweep: boolean;
226
+ x: number;
227
+ y: number;
228
+ } | {
229
+ type: 'Z';
230
+ };
231
+ interface BaseShape {
232
+ id: string;
233
+ type: ShapeType;
234
+ style: Style;
235
+ transform: Matrix3;
236
+ _bounds?: {
237
+ x: number;
238
+ y: number;
239
+ width: number;
240
+ height: number;
241
+ };
242
+ }
243
+ interface GroupShape extends BaseShape {
244
+ type: 'group';
245
+ children: Shape[];
246
+ }
247
+ interface PathShape extends BaseShape {
248
+ type: 'path';
249
+ commands: PathCommand[];
250
+ }
251
+ interface RectShape extends BaseShape {
252
+ type: 'rect';
253
+ x: number;
254
+ y: number;
255
+ width: number;
256
+ height: number;
257
+ rx?: number;
258
+ ry?: number;
259
+ }
260
+ interface CircleShape extends BaseShape {
261
+ type: 'circle';
262
+ cx: number;
263
+ cy: number;
264
+ r: number;
265
+ }
266
+ interface EllipseShape extends BaseShape {
267
+ type: 'ellipse';
268
+ cx: number;
269
+ cy: number;
270
+ rx: number;
271
+ ry: number;
272
+ }
273
+ interface LineShape extends BaseShape {
274
+ type: 'line';
275
+ x1: number;
276
+ y1: number;
277
+ x2: number;
278
+ y2: number;
279
+ }
280
+ interface PolylineShape extends BaseShape {
281
+ type: 'polyline';
282
+ points: Vector2[];
283
+ }
284
+ interface PolygonShape extends BaseShape {
285
+ type: 'polygon';
286
+ points: Vector2[];
287
+ }
288
+ interface TextShape extends BaseShape {
289
+ type: 'text';
290
+ style: TextStyle;
291
+ x: number;
292
+ y: number;
293
+ content: string;
294
+ }
295
+ interface ArcShape extends BaseShape {
296
+ type: 'arc';
297
+ cx: number;
298
+ cy: number;
299
+ r: number;
300
+ startAngle: number;
301
+ endAngle: number;
302
+ }
303
+ interface TexShape extends BaseShape {
304
+ type: 'tex';
305
+ x: number;
306
+ y: number;
307
+ latex: string;
308
+ html: string;
309
+ fontSize: number;
310
+ color: string;
311
+ }
312
+ interface SVGShape extends BaseShape {
313
+ type: 'svg';
314
+ content: string;
315
+ width: number;
316
+ height: number;
317
+ originalWidth: number;
318
+ originalHeight: number;
319
+ viewBox?: string;
320
+ }
321
+ interface ImageShape extends BaseShape {
322
+ type: 'image';
323
+ src: string;
324
+ width: number;
325
+ height: number;
326
+ cornerRadius?: number;
327
+ }
328
+ type Shape = GroupShape | PathShape | RectShape | CircleShape | EllipseShape | LineShape | PolylineShape | PolygonShape | TextShape | ArcShape | TexShape | SVGShape | ImageShape;
329
+ interface FrameConfig {
330
+ /** 逻辑宽度(默认 16) */
331
+ width: number;
332
+ /** 逻辑高度(默认 9,16:9 比例) */
333
+ height: number;
334
+ }
335
+ interface RenderOptions {
336
+ /** 画布像素宽度 */
337
+ width?: number;
338
+ /** 画布像素高度 */
339
+ height?: number;
340
+ /** 背景颜色 */
341
+ background?: string;
342
+ /**
343
+ * Frame 配置(Manim 风格坐标系)
344
+ *
345
+ * 启用后:
346
+ * - 原点在画布中心
347
+ * - Y 轴向上为正
348
+ * - 图形使用逻辑坐标,自动映射到像素
349
+ *
350
+ * 可以是 boolean(使用默认 16:9 frame)或 FrameConfig 对象
351
+ */
352
+ frame?: boolean | FrameConfig;
353
+ /** 手绘风格 */
354
+ rough?: boolean;
355
+ roughness?: number;
356
+ bowing?: number;
357
+ seed?: number;
358
+ }
359
+ interface SliderOptions {
360
+ min: number;
361
+ max: number;
362
+ value?: number;
363
+ step?: number;
364
+ label?: string;
365
+ showPlayButton?: boolean;
366
+ playDuration?: number;
367
+ }
368
+ interface LocatorOptions {
369
+ x: number;
370
+ y: number;
371
+ radius?: number;
372
+ constraint?: (p: Vector2) => Vector2;
373
+ }
374
+ interface AnimationOptions {
375
+ duration?: number;
376
+ easing?: string;
377
+ delay?: number;
378
+ lagRatio?: number;
379
+ }
380
+
381
+ /**
382
+ * @locusing/animate - 时间线引擎
383
+ *
384
+ * 基于 GSAP 的动画时间线管理
385
+ */
386
+ type AnimationStatus = 'pending' | 'running' | 'paused' | 'completed';
387
+ interface TimelineOptions {
388
+ duration?: number;
389
+ easing?: string;
390
+ delay?: number;
391
+ repeat?: number;
392
+ yoyo?: boolean;
393
+ onStart?: () => void;
394
+ onComplete?: () => void;
395
+ onUpdate?: (progress: number) => void;
396
+ }
397
+ /**
398
+ * Timeline 类 - 动画时间线管理
399
+ */
400
+ declare class Timeline {
401
+ private timeline;
402
+ private _status;
403
+ constructor(options?: TimelineOptions);
404
+ /** 当前状态 */
405
+ get status(): AnimationStatus;
406
+ /** 当前进度 (0-1) */
407
+ get progress(): number;
408
+ /** 总时长 */
409
+ get duration(): number;
410
+ /** 当前时间 */
411
+ get time(): number;
412
+ /**
413
+ * 添加动画到时间线
414
+ */
415
+ add(target: object | string, vars: gsap.TweenVars, position?: gsap.Position): this;
416
+ /**
417
+ * 添加回调函数
418
+ */
419
+ call(callback: () => void, position?: gsap.Position): this;
420
+ /**
421
+ * 添加延迟
422
+ */
423
+ delay(seconds: number, position?: gsap.Position): this;
424
+ /**
425
+ * 添加标签
426
+ */
427
+ label(name: string, position?: gsap.Position): this;
428
+ /**
429
+ * 播放
430
+ */
431
+ play(): this;
432
+ /**
433
+ * 暂停
434
+ */
435
+ pause(): this;
436
+ /**
437
+ * 恢复
438
+ */
439
+ resume(): this;
440
+ /**
441
+ * 停止并重置
442
+ */
443
+ restart(): this;
444
+ /**
445
+ * 跳转到指定时间
446
+ */
447
+ seek(time: number | string): this;
448
+ /**
449
+ * 设置进度
450
+ */
451
+ setProgress(progress: number): this;
452
+ /**
453
+ * 设置速度
454
+ */
455
+ setSpeed(speed: number): this;
456
+ /**
457
+ * 反向播放
458
+ */
459
+ reverse(): this;
460
+ /**
461
+ * 销毁
462
+ */
463
+ kill(): void;
464
+ /**
465
+ * 等待完成
466
+ */
467
+ finished(): Promise<void>;
468
+ }
469
+ /**
470
+ * 创建时间线
471
+ */
472
+ declare function createTimeline(options?: TimelineOptions): Timeline;
473
+ /**
474
+ * GSAP 缓动函数映射
475
+ */
476
+ declare const easingMap: Record<string, string>;
477
+ /**
478
+ * 获取 GSAP 缓动字符串
479
+ */
480
+ declare function getGSAPEasing(easing: string): string;
481
+
482
+ /**
483
+ * Camera - 基础相机系统
484
+ *
485
+ * 控制 SVG 视口的位置和缩放
486
+ */
487
+
488
+ /**
489
+ * 相机配置
490
+ */
491
+ interface CameraConfig {
492
+ /** 视口中心位置 */
493
+ frameCenter?: Vector2;
494
+ /** 视口宽度 */
495
+ frameWidth?: number;
496
+ /** 视口高度 */
497
+ frameHeight?: number;
498
+ }
499
+ /**
500
+ * 视口帧
501
+ */
502
+ interface Frame {
503
+ x: number;
504
+ y: number;
505
+ width: number;
506
+ height: number;
507
+ }
508
+ /**
509
+ * Camera 类
510
+ *
511
+ * 管理 SVG 视口,支持平移和缩放
512
+ */
513
+ declare class Camera {
514
+ protected _center: Vector2;
515
+ protected _width: number;
516
+ protected _height: number;
517
+ /**
518
+ * 创建相机
519
+ * @param config - 相机配置
520
+ */
521
+ constructor(config?: CameraConfig);
522
+ /**
523
+ * 获取视口中心
524
+ */
525
+ get center(): Vector2;
526
+ /**
527
+ * 设置视口中心
528
+ */
529
+ set center(value: Vector2);
530
+ /**
531
+ * 获取视口宽度
532
+ */
533
+ get width(): number;
534
+ /**
535
+ * 设置视口宽度
536
+ */
537
+ set width(value: number);
538
+ /**
539
+ * 获取视口高度
540
+ */
541
+ get height(): number;
542
+ /**
543
+ * 设置视口高度
544
+ */
545
+ set height(value: number);
546
+ /**
547
+ * 获取可视区域
548
+ */
549
+ getFrame(): Frame;
550
+ /**
551
+ * 移动相机到指定位置
552
+ * @param point - 目标位置
553
+ */
554
+ moveTo(point: Vector2): this;
555
+ /**
556
+ * 相对移动相机
557
+ * @param delta - 移动增量
558
+ */
559
+ moveBy(delta: Vector2): this;
560
+ /**
561
+ * 缩放视口
562
+ * @param factor - 缩放因子(>1 缩小视野,<1 放大视野)
563
+ */
564
+ zoom(factor: number): this;
565
+ /**
566
+ * 设置视口大小
567
+ * @param width - 宽度
568
+ * @param height - 高度
569
+ */
570
+ setSize(width: number, height: number): this;
571
+ /**
572
+ * 重置相机到初始状态
573
+ */
574
+ reset(): this;
575
+ /**
576
+ * 获取 SVG viewBox 字符串
577
+ */
578
+ getViewBox(): string;
579
+ /**
580
+ * 应用相机设置到 SVG 元素
581
+ * @param svg - SVG 元素
582
+ */
583
+ applyToSVG(svg: SVGSVGElement): void;
584
+ /**
585
+ * 将屏幕坐标转换为世界坐标
586
+ * @param screenPoint - 屏幕坐标
587
+ * @param svgWidth - SVG 元素宽度
588
+ * @param svgHeight - SVG 元素高度
589
+ */
590
+ screenToWorld(screenPoint: Vector2, svgWidth: number, svgHeight: number): Vector2;
591
+ /**
592
+ * 将世界坐标转换为屏幕坐标
593
+ * @param worldPoint - 世界坐标
594
+ * @param svgWidth - SVG 元素宽度
595
+ * @param svgHeight - SVG 元素高度
596
+ */
597
+ worldToScreen(worldPoint: Vector2, svgWidth: number, svgHeight: number): Vector2;
598
+ /**
599
+ * 检查点是否在视口内
600
+ * @param point - 要检查的点
601
+ */
602
+ isPointInView(point: Vector2): boolean;
603
+ /**
604
+ * 获取当前缩放级别
605
+ * @param baseWidth - 基准宽度(默认 400)
606
+ */
607
+ getZoomLevel(baseWidth?: number): number;
608
+ /**
609
+ * 设置缩放级别
610
+ * @param level - 目标缩放级别
611
+ * @param baseWidth - 基准宽度(默认 400)
612
+ */
613
+ setZoomLevel(level: number, baseWidth?: number): this;
614
+ /**
615
+ * 克隆相机
616
+ */
617
+ clone(): Camera;
618
+ }
619
+ /**
620
+ * 创建相机
621
+ * @param config - 相机配置
622
+ */
623
+ declare function createCamera(config?: CameraConfig): Camera;
624
+
625
+ /**
626
+ * @locusing/animate - Scene 场景管理
627
+ *
628
+ * Manim 风格的场景类
629
+ */
630
+
631
+ /** 预设配置类型 */
632
+ type ScenePreset = 'default' | 'manim';
633
+ interface SceneConfig {
634
+ width?: number;
635
+ height?: number;
636
+ background?: string;
637
+ fps?: number;
638
+ rough?: boolean;
639
+ /** 相机配置 */
640
+ camera?: CameraConfig;
641
+ /**
642
+ * 预设配置
643
+ * - 'default': Locusing 默认 (16×9)
644
+ * - 'manim': Manim 兼容模式 (14.22×8)
645
+ */
646
+ preset?: ScenePreset;
647
+ /**
648
+ * 是否自动适配容器比例
649
+ * 当为 true 且未指定 camera.frameWidth/frameHeight 时,
650
+ * 会根据容器的宽高比自动计算 frame 尺寸
651
+ * @default false
652
+ */
653
+ autoFitFrame?: boolean;
654
+ }
655
+ /**
656
+ * Scene 类 - Manim 风格的场景管理
657
+ *
658
+ * 使用方式一:继承并实现 construct 方法
659
+ * ```typescript
660
+ * class MyScene extends Scene {
661
+ * construct() {
662
+ * const sq = square(0.5).fill('#EA580C');
663
+ * this.play(Create(sq));
664
+ * this.wait(1);
665
+ * this.play(FadeOut(sq));
666
+ * }
667
+ * }
668
+ * // 在编辑器或文档中使用
669
+ * play(MyScene);
670
+ * ```
671
+ *
672
+ * 使用方式二:传入容器直接使用
673
+ * ```typescript
674
+ * const scene = new MyScene();
675
+ * scene.setup(svgElement, { width: 800, height: 600 });
676
+ * scene.construct();
677
+ * ```
678
+ */
679
+ /** 内部配置类型(不包含 camera,因为 camera 作为独立实例管理) */
680
+ interface InternalSceneConfig {
681
+ width: number;
682
+ height: number;
683
+ background: string;
684
+ fps: number;
685
+ rough: boolean;
686
+ }
687
+ /** Updater 函数类型 */
688
+ type UpdaterFunction = (diagram: Diagram, dt: number) => void;
689
+ /** Updater 配置 */
690
+ interface UpdaterConfig {
691
+ /** Updater 函数 */
692
+ fn: UpdaterFunction;
693
+ /** 关联的图形 */
694
+ diagram: Diagram;
695
+ }
696
+ declare abstract class Scene {
697
+ protected container: HTMLElement | SVGSVGElement;
698
+ protected svg: SVGSVGElement;
699
+ /** Y 轴翻转组,所有内容都渲染到这个组中 */
700
+ protected flipGroup: SVGGElement;
701
+ protected config: InternalSceneConfig;
702
+ protected timeline: Timeline;
703
+ protected objects: Map<string, Diagram>;
704
+ protected currentTime: number;
705
+ protected _isSetup: boolean;
706
+ /** Frame 逻辑尺寸(用于坐标系统) */
707
+ protected frameWidth: number;
708
+ protected frameHeight: number;
709
+ /** 相机实例 */
710
+ camera: Camera;
711
+ /** Updaters 列表 */
712
+ protected updaters: UpdaterConfig[];
713
+ /** 上一帧时间(用于计算 dt) */
714
+ protected lastFrameTime: number;
715
+ /** 动画帧 ID */
716
+ protected animationFrameId: number | null;
717
+ /** 更新是否暂停 */
718
+ protected updatesSuspended: boolean;
719
+ /**
720
+ * 创建 Scene 实例
721
+ * @param container - 可选的容器元素。如果不传,需要后续调用 setup() 方法
722
+ * @param config - 场景配置
723
+ */
724
+ constructor(container?: HTMLElement | SVGSVGElement, config?: SceneConfig);
725
+ /**
726
+ * 初始化场景(内部方法)
727
+ */
728
+ private initScene;
729
+ /**
730
+ * 更新相机的 viewBox 到 SVG
731
+ * 在相机移动或缩放后调用此方法
732
+ */
733
+ updateCameraViewBox(): void;
734
+ /**
735
+ * 设置场景(延迟初始化)
736
+ * 用于编辑器和文档中的使用场景,在实例化后调用
737
+ *
738
+ * @param svgOrContainer - SVG 元素或容器元素
739
+ * @param config - 场景配置
740
+ */
741
+ setup(svgOrContainer: SVGSVGElement | HTMLElement, config?: SceneConfig): void;
742
+ /** 子类实现此方法来构建动画 */
743
+ abstract construct(): void | Promise<void>;
744
+ /**
745
+ * 添加图形到场景(不带动画)
746
+ */
747
+ add(...diagrams: Diagram[]): void;
748
+ /**
749
+ * 从场景移除图形
750
+ */
751
+ remove(...diagrams: Diagram[]): void;
752
+ /**
753
+ * 播放动画
754
+ *
755
+ * 支持 Animation、AnimateProxy 和 AnimationConfig
756
+ *
757
+ * @param args - 动画、AnimateProxy 或配置
758
+ *
759
+ * @example
760
+ * ```typescript
761
+ * // 普通动画
762
+ * this.play(Create(circle));
763
+ *
764
+ * // Manim 风格的 .animate 语法
765
+ * this.play(circle.animate.shift([2, 0]).scale(2));
766
+ *
767
+ * // 多个动画
768
+ * this.play(Create(circle), Create(square));
769
+ *
770
+ * // 带配置
771
+ * this.play(Create(circle), { lagRatio: 0.5 });
772
+ * ```
773
+ */
774
+ play(...args: (Animation | AnimateProxy | AnimationConfig)[]): void;
775
+ /**
776
+ * 等待指定时间
777
+ */
778
+ wait(seconds?: number): void;
779
+ /**
780
+ * 为图形添加 updater
781
+ *
782
+ * Updater 会在每一帧被调用,用于创建动态效果
783
+ *
784
+ * @param diagram - 要添加 updater 的图形
785
+ * @param fn - updater 函数,接收图形和时间增量
786
+ *
787
+ * @example
788
+ * ```typescript
789
+ * const dot = circle(0.1).fill('#EA580C');
790
+ * this.add(dot);
791
+ *
792
+ * // 让 dot 跟随鼠标或按时间变化
793
+ * this.addUpdater(dot, (d, dt) => {
794
+ * const t = this.getTime();
795
+ * return d.move([Math.cos(t), Math.sin(t)]);
796
+ * });
797
+ * ```
798
+ */
799
+ addUpdater(diagram: Diagram, fn: UpdaterFunction): void;
800
+ /**
801
+ * 移除图形的 updater
802
+ */
803
+ removeUpdater(diagram: Diagram, fn?: UpdaterFunction): void;
804
+ /**
805
+ * 清除所有 updaters
806
+ */
807
+ clearUpdaters(): void;
808
+ /**
809
+ * 获取图形的所有 updaters
810
+ *
811
+ * @param diagram - 可选,指定图形。如果不传则返回所有 updaters
812
+ */
813
+ getUpdaters(diagram?: Diagram): UpdaterFunction[];
814
+ /**
815
+ * 暂停更新
816
+ *
817
+ * 暂停所有 updater 的执行,直到调用 resumeUpdating()
818
+ */
819
+ suspendUpdating(): void;
820
+ /**
821
+ * 恢复更新
822
+ *
823
+ * 恢复所有 updater 的执行
824
+ */
825
+ resumeUpdating(): void;
826
+ /**
827
+ * 检查更新是否暂停
828
+ */
829
+ isUpdatingSuspended(): boolean;
830
+ /**
831
+ * 获取当前时间(秒)
832
+ */
833
+ getTime(): number;
834
+ /**
835
+ * 启动帧循环(用于 updaters)
836
+ */
837
+ protected startFrameLoop(): void;
838
+ /**
839
+ * 停止帧循环
840
+ */
841
+ protected stopFrameLoop(): void;
842
+ /**
843
+ * 运行场景
844
+ */
845
+ render(): Promise<void>;
846
+ /**
847
+ * 启动动画播放
848
+ * 调用此方法开始播放 construct() 中构建的动画
849
+ *
850
+ * @returns Promise 在动画完成后 resolve
851
+ */
852
+ start(): Promise<void>;
853
+ /**
854
+ * 渲染单个图形到 SVG(使用 Frame 模式)
855
+ */
856
+ protected renderDiagram(diagram: Diagram): SVGElement | null;
857
+ /**
858
+ * 获取图形对应的 SVG 元素
859
+ */
860
+ getElement(diagram: Diagram): SVGElement | null;
861
+ /**
862
+ * 获取或创建图形元素
863
+ */
864
+ getOrCreateElement(diagram: Diagram): SVGElement;
865
+ /**
866
+ * 更新场景中的对象映射
867
+ *
868
+ * 用于在动画完成后将旧对象替换为新对象
869
+ *
870
+ * @param oldDiagram - 旧图形
871
+ * @param newDiagram - 新图形
872
+ */
873
+ updateObject(oldDiagram: Diagram, newDiagram: Diagram): void;
874
+ /**
875
+ * 获取 SVG 容器
876
+ */
877
+ getSVG(): SVGSVGElement;
878
+ /**
879
+ * 获取配置
880
+ */
881
+ getConfig(): InternalSceneConfig;
882
+ /**
883
+ * 导出为 SVG 字符串
884
+ */
885
+ toSVGString(): string;
886
+ /**
887
+ * 暂停
888
+ */
889
+ pause(): void;
890
+ /**
891
+ * 恢复
892
+ */
893
+ resume(): void;
894
+ /**
895
+ * 重新开始
896
+ */
897
+ restart(): void;
898
+ /**
899
+ * 销毁场景
900
+ */
901
+ destroy(): void;
902
+ }
903
+ /**
904
+ * 创建简单场景(不需要继承)
905
+ */
906
+ declare function createScene(container: HTMLElement, buildFn: (scene: SimpleScene) => void, config?: SceneConfig): SimpleScene;
907
+ declare class SimpleScene extends Scene {
908
+ private buildFn;
909
+ constructor(container: HTMLElement, buildFn: (scene: SimpleScene) => void, config?: SceneConfig);
910
+ construct(): void;
911
+ }
912
+
913
+ /**
914
+ * @locusing/animate - 动画类型定义
915
+ */
916
+
917
+ /**
918
+ * 动画配置
919
+ */
920
+ interface AnimationConfig {
921
+ duration?: number;
922
+ easing?: string;
923
+ delay?: number;
924
+ lagRatio?: number;
925
+ runTime?: number;
926
+ }
927
+ /**
928
+ * 动画接口
929
+ */
930
+ interface Animation {
931
+ /** 动画时长 */
932
+ duration: number;
933
+ /** 目标图形 */
934
+ target: Diagram;
935
+ /** 执行动画 */
936
+ execute(scene: Scene, timeline: Timeline, startTime: number): void;
937
+ }
938
+ /**
939
+ * 创建动画选项
940
+ */
941
+ interface CreateOptions extends AnimationConfig {
942
+ /** 是否先描边再填充 */
943
+ drawBorderThenFill?: boolean;
944
+ }
945
+ /**
946
+ * 淡入淡出选项
947
+ */
948
+ interface FadeOptions extends AnimationConfig {
949
+ /** 方向 */
950
+ direction?: Vector2 | 'UP' | 'DOWN' | 'LEFT' | 'RIGHT';
951
+ /** 位移距离 */
952
+ shift?: number;
953
+ }
954
+ /**
955
+ * 变换选项
956
+ */
957
+ interface TransformOptions extends AnimationConfig {
958
+ /** 路径函数 */
959
+ pathFunc?: (t: number) => Vector2;
960
+ /** 是否替换原对象 */
961
+ replace?: boolean;
962
+ }
963
+ /**
964
+ * 移动选项
965
+ */
966
+ interface MoveOptions extends AnimationConfig {
967
+ /** 路径 */
968
+ path?: Diagram;
969
+ /** 是否旋转跟随路径 */
970
+ rotateAlongPath?: boolean;
971
+ }
972
+ /**
973
+ * 旋转选项
974
+ */
975
+ interface RotateOptions extends AnimationConfig {
976
+ /** 旋转中心 */
977
+ aboutPoint?: Vector2;
978
+ /** 旋转角度(弧度) */
979
+ angle?: number;
980
+ }
981
+ /**
982
+ * 缩放选项
983
+ */
984
+ interface ScaleOptions extends AnimationConfig {
985
+ /** 缩放中心 */
986
+ aboutPoint?: Vector2;
987
+ /** 缩放因子 */
988
+ factor?: number;
989
+ }
990
+ /**
991
+ * 指示动画选项
992
+ */
993
+ interface IndicateOptions extends AnimationConfig {
994
+ /** 高亮颜色 */
995
+ color?: string;
996
+ /** 缩放因子 */
997
+ scaleFactor?: number;
998
+ }
999
+ /**
1000
+ * 圈出选项
1001
+ */
1002
+ interface CircumscribeOptions extends AnimationConfig {
1003
+ /** 形状:圆形或矩形 */
1004
+ shape?: 'circle' | 'rectangle';
1005
+ /** 颜色 */
1006
+ color?: string;
1007
+ /** 线条宽度 */
1008
+ strokeWidth?: number;
1009
+ /** 填充 */
1010
+ fill?: boolean;
1011
+ /** 填充透明度 */
1012
+ fillOpacity?: number;
1013
+ }
1014
+ /**
1015
+ * 闪光选项
1016
+ */
1017
+ interface FlashOptions extends AnimationConfig {
1018
+ /** 颜色 */
1019
+ color?: string;
1020
+ /** 线条数量 */
1021
+ lineLength?: number;
1022
+ /** 线条数量 */
1023
+ numLines?: number;
1024
+ }
1025
+ /**
1026
+ * 抖动选项
1027
+ */
1028
+ interface WiggleOptions extends AnimationConfig {
1029
+ /** 抖动次数 */
1030
+ nWiggles?: number;
1031
+ /** 抖动幅度 */
1032
+ scaleValue?: number;
1033
+ /** 旋转角度 */
1034
+ rotationAngle?: number;
1035
+ }
1036
+ /**
1037
+ * 动画组选项
1038
+ */
1039
+ interface AnimationGroupOptions extends AnimationConfig {
1040
+ /** 错开比例 */
1041
+ lagRatio?: number;
1042
+ }
1043
+ /**
1044
+ * ValueTracker - 用于跟踪数值变化
1045
+ */
1046
+ declare class ValueTracker {
1047
+ private _value;
1048
+ private listeners;
1049
+ constructor(initialValue?: number);
1050
+ get value(): number;
1051
+ set value(newValue: number);
1052
+ /** 添加变化监听器 */
1053
+ addListener(listener: (value: number) => void): () => void;
1054
+ /** 创建动画目标对象 */
1055
+ animate(targetValue: number): {
1056
+ value: number;
1057
+ };
1058
+ /** 获取当前值的普通对象(用于 GSAP) */
1059
+ toObject(): {
1060
+ value: number;
1061
+ };
1062
+ }
1063
+ /**
1064
+ * ComplexValueTracker - 用于跟踪复数值变化
1065
+ *
1066
+ * 支持实部和虚部的独立动画,以及极坐标形式的动画
1067
+ *
1068
+ * @example
1069
+ * ```typescript
1070
+ * const tracker = new ComplexValueTracker({ re: 1, im: 0 });
1071
+ *
1072
+ * // 监听变化
1073
+ * tracker.addListener(z => {
1074
+ * console.log(`当前值: ${z.re} + ${z.im}i`);
1075
+ * });
1076
+ *
1077
+ * // 设置新值
1078
+ * tracker.value = { re: 0, im: 1 };
1079
+ * ```
1080
+ */
1081
+ declare class ComplexValueTracker {
1082
+ private _re;
1083
+ private _im;
1084
+ private listeners;
1085
+ constructor(initialValue?: {
1086
+ re: number;
1087
+ im: number;
1088
+ });
1089
+ /** 获取复数值 */
1090
+ get value(): {
1091
+ re: number;
1092
+ im: number;
1093
+ };
1094
+ /** 设置复数值 */
1095
+ set value(newValue: {
1096
+ re: number;
1097
+ im: number;
1098
+ });
1099
+ /** 获取实部 */
1100
+ get re(): number;
1101
+ /** 设置实部 */
1102
+ set re(value: number);
1103
+ /** 获取虚部 */
1104
+ get im(): number;
1105
+ /** 设置虚部 */
1106
+ set im(value: number);
1107
+ /** 获取模(绝对值) */
1108
+ get modulus(): number;
1109
+ /** 设置模(保持辐角不变) */
1110
+ set modulus(r: number);
1111
+ /** 获取辐角(弧度) */
1112
+ get argument(): number;
1113
+ /** 设置辐角(保持模不变) */
1114
+ set argument(theta: number);
1115
+ /** 通知所有监听器 */
1116
+ private notifyListeners;
1117
+ /** 添加变化监听器 */
1118
+ addListener(listener: (value: {
1119
+ re: number;
1120
+ im: number;
1121
+ }) => void): () => void;
1122
+ /** 创建动画目标对象(用于 GSAP) */
1123
+ animate(targetValue: {
1124
+ re: number;
1125
+ im: number;
1126
+ }): {
1127
+ re: number;
1128
+ im: number;
1129
+ };
1130
+ /** 创建极坐标动画目标对象(用于 GSAP) */
1131
+ animatePolar(targetModulus: number, targetArgument: number): {
1132
+ modulus: number;
1133
+ argument: number;
1134
+ };
1135
+ /** 获取当前值的普通对象(用于 GSAP) */
1136
+ toObject(): {
1137
+ re: number;
1138
+ im: number;
1139
+ };
1140
+ /** 获取极坐标形式的普通对象(用于 GSAP) */
1141
+ toPolarObject(): {
1142
+ modulus: number;
1143
+ argument: number;
1144
+ };
1145
+ /** 从极坐标设置值 */
1146
+ setPolar(r: number, theta: number): void;
1147
+ /** 获取共轭复数 */
1148
+ conjugate(): {
1149
+ re: number;
1150
+ im: number;
1151
+ };
1152
+ /** 复数加法 */
1153
+ add(other: {
1154
+ re: number;
1155
+ im: number;
1156
+ }): void;
1157
+ /** 复数乘法 */
1158
+ multiply(other: {
1159
+ re: number;
1160
+ im: number;
1161
+ }): void;
1162
+ /** 标量乘法 */
1163
+ scale(k: number): void;
1164
+ }
1165
+
1166
+ /**
1167
+ * AnimateProxy - Manim 风格的 .animate 语法支持
1168
+ *
1169
+ * 实现链式操作记录,用于创建从当前状态到目标状态的动画
1170
+ *
1171
+ * @example
1172
+ * ```typescript
1173
+ * // Manim 风格
1174
+ * await scene.play(circle.animate.shift([2, 0]).scale(2));
1175
+ *
1176
+ * // 等价于
1177
+ * const target = circle.shift([2, 0]).scale(2);
1178
+ * await scene.play(Transform(circle, target));
1179
+ * ```
1180
+ */
1181
+
1182
+ /**
1183
+ * 操作类型
1184
+ */
1185
+ type Operation = {
1186
+ type: 'translate';
1187
+ x: number;
1188
+ y: number;
1189
+ } | {
1190
+ type: 'shift';
1191
+ x: number;
1192
+ y: number;
1193
+ } | {
1194
+ type: 'move';
1195
+ x: number;
1196
+ y: number;
1197
+ } | {
1198
+ type: 'position';
1199
+ x: number;
1200
+ y: number;
1201
+ } | {
1202
+ type: 'rotate';
1203
+ radians: number;
1204
+ center: Vector2 | undefined;
1205
+ } | {
1206
+ type: 'rotateDeg';
1207
+ degrees: number;
1208
+ center: Vector2 | undefined;
1209
+ } | {
1210
+ type: 'scale';
1211
+ sx: number;
1212
+ sy: number;
1213
+ center: Vector2 | undefined;
1214
+ } | {
1215
+ type: 'transform';
1216
+ matrix: Matrix3;
1217
+ } | {
1218
+ type: 'style';
1219
+ style: Partial<Style>;
1220
+ } | {
1221
+ type: 'fill';
1222
+ color: string;
1223
+ } | {
1224
+ type: 'stroke';
1225
+ color: string;
1226
+ } | {
1227
+ type: 'strokeWidth';
1228
+ width: number;
1229
+ } | {
1230
+ type: 'opacity';
1231
+ value: number;
1232
+ } | {
1233
+ type: 'setColor';
1234
+ color: string;
1235
+ } | {
1236
+ type: 'nextTo';
1237
+ target: Diagram | Vector2;
1238
+ direction: Vector2;
1239
+ buffer: number;
1240
+ } | {
1241
+ type: 'alignTo';
1242
+ other: Diagram;
1243
+ direction: Vector2;
1244
+ } | {
1245
+ type: 'centerOnOrigin';
1246
+ } | {
1247
+ type: 'flip';
1248
+ axis: Vector2;
1249
+ } | {
1250
+ type: 'stretch';
1251
+ factor: number;
1252
+ dimension: 0 | 1;
1253
+ };
1254
+ /**
1255
+ * AnimateProxy - 动画代理类
1256
+ *
1257
+ * 记录对 Diagram 的操作链,生成动画
1258
+ */
1259
+ declare class AnimateProxy {
1260
+ private diagram;
1261
+ private operations;
1262
+ private config;
1263
+ constructor(diagram: Diagram);
1264
+ /**
1265
+ * 设置动画时长
1266
+ */
1267
+ duration(seconds: number): AnimateProxy;
1268
+ /**
1269
+ * 设置动画缓动函数
1270
+ */
1271
+ easing(easing: string): AnimateProxy;
1272
+ /**
1273
+ * 设置动画运行时间(Manim 风格)
1274
+ */
1275
+ runTime(seconds: number): AnimateProxy;
1276
+ /**
1277
+ * 平移
1278
+ */
1279
+ translate(x: number, y: number): AnimateProxy;
1280
+ translate(v: Vector2): AnimateProxy;
1281
+ /**
1282
+ * 相对移动(偏移)
1283
+ */
1284
+ shift(x: number, y: number): AnimateProxy;
1285
+ shift(v: Vector2): AnimateProxy;
1286
+ /**
1287
+ * 移动到指定位置
1288
+ */
1289
+ move(x: number, y: number): AnimateProxy;
1290
+ move(v: Vector2): AnimateProxy;
1291
+ /**
1292
+ * 移动到指定位置(别名)
1293
+ */
1294
+ position(x: number, y: number): AnimateProxy;
1295
+ position(v: Vector2): AnimateProxy;
1296
+ /**
1297
+ * 移动到指定位置(Manim 风格别名)
1298
+ */
1299
+ moveTo(x: number, y: number): AnimateProxy;
1300
+ moveTo(v: Vector2): AnimateProxy;
1301
+ /**
1302
+ * 旋转(弧度)
1303
+ */
1304
+ rotate(radians: number, center?: Vector2): AnimateProxy;
1305
+ /**
1306
+ * 旋转(度数)
1307
+ */
1308
+ rotateDeg(degrees: number, center?: Vector2): AnimateProxy;
1309
+ /**
1310
+ * 缩放
1311
+ */
1312
+ scale(factor: number, center?: Vector2): AnimateProxy;
1313
+ scale(sx: number, sy: number, center?: Vector2): AnimateProxy;
1314
+ /**
1315
+ * 应用变换矩阵
1316
+ */
1317
+ transform(matrix: Matrix3): AnimateProxy;
1318
+ /**
1319
+ * 翻转(沿指定轴)
1320
+ */
1321
+ flip(axis?: Vector2): AnimateProxy;
1322
+ /**
1323
+ * 单向拉伸
1324
+ */
1325
+ stretch(factor: number, dimension: 0 | 1): AnimateProxy;
1326
+ /**
1327
+ * 设置填充颜色
1328
+ */
1329
+ fill(color: string): AnimateProxy;
1330
+ /**
1331
+ * 设置描边颜色
1332
+ */
1333
+ stroke(color: string): AnimateProxy;
1334
+ /**
1335
+ * 设置描边宽度
1336
+ */
1337
+ strokeWidth(width: number): AnimateProxy;
1338
+ /**
1339
+ * 设置透明度
1340
+ */
1341
+ opacity(value: number): AnimateProxy;
1342
+ /**
1343
+ * 批量设置样式
1344
+ */
1345
+ style(newStyle: Partial<Style>): AnimateProxy;
1346
+ /**
1347
+ * 同时设置填充和描边颜色(Manim 风格)
1348
+ */
1349
+ setColor(color: string): AnimateProxy;
1350
+ /**
1351
+ * 相对定位
1352
+ */
1353
+ nextTo(target: Diagram | Vector2, direction: Vector2, buffer?: number): AnimateProxy;
1354
+ /**
1355
+ * 对齐到另一个图形
1356
+ */
1357
+ alignTo(other: Diagram, direction: Vector2): AnimateProxy;
1358
+ /**
1359
+ * 将中心对齐到原点
1360
+ */
1361
+ centerOnOrigin(): AnimateProxy;
1362
+ /**
1363
+ * 构建目标 Diagram
1364
+ *
1365
+ * 应用所有记录的操作,返回最终状态的 Diagram
1366
+ */
1367
+ build(): Diagram;
1368
+ /**
1369
+ * 获取源 Diagram
1370
+ */
1371
+ getSource(): Diagram;
1372
+ /**
1373
+ * 获取动画配置
1374
+ */
1375
+ getConfig(): AnimationConfig;
1376
+ /**
1377
+ * 获取操作列表
1378
+ */
1379
+ getOperations(): Operation[];
1380
+ }
1381
+
1382
+ /**
1383
+ * @locusing/core - Diagram 不可变图形树
1384
+ *
1385
+ * 实现链式 API,支持声明式图形构造
1386
+ */
1387
+
1388
+ /**
1389
+ * Diagram 类 - 不可变图形树的包装器
1390
+ *
1391
+ * 每个方法返回新的 Diagram 实例,保证不可变性
1392
+ */
1393
+ declare class Diagram {
1394
+ readonly shape: Shape;
1395
+ constructor(shape: Shape);
1396
+ /** 设置填充颜色 */
1397
+ fill(color: string): Diagram;
1398
+ /** 设置描边颜色 */
1399
+ stroke(color: string): Diagram;
1400
+ /** 设置描边宽度 */
1401
+ strokeWidth(width: number): Diagram;
1402
+ /** 设置透明度 */
1403
+ opacity(value: number): Diagram;
1404
+ /** 设置虚线样式 */
1405
+ dashed(dasharray?: string): Diagram;
1406
+ /** 批量设置样式 */
1407
+ style(newStyle: Partial<Style>): Diagram;
1408
+ /**
1409
+ * 渐隐效果 - 设置透明度
1410
+ *
1411
+ * @param darkness 暗度值 0-1,0 完全可见,1 完全透明
1412
+ * @returns 新的 Diagram
1413
+ *
1414
+ * @example
1415
+ * ```typescript
1416
+ * square(1).fade(0.5) // 50% 透明
1417
+ * square(1).fade(1) // 完全透明
1418
+ * square(1).fade(0) // 完全可见
1419
+ * ```
1420
+ */
1421
+ fade(darkness?: number): Diagram;
1422
+ /**
1423
+ * 设置填充透明度
1424
+ */
1425
+ fillOpacity(value: number): Diagram;
1426
+ /**
1427
+ * 设置描边透明度
1428
+ */
1429
+ strokeOpacity(value: number): Diagram;
1430
+ /**
1431
+ * 获取填充颜色
1432
+ */
1433
+ getFillColor(): string | undefined;
1434
+ /**
1435
+ * 获取描边颜色
1436
+ */
1437
+ getStrokeColor(): string | undefined;
1438
+ /**
1439
+ * 获取描边宽度
1440
+ */
1441
+ getStrokeWidth(): number | undefined;
1442
+ /**
1443
+ * 获取透明度
1444
+ */
1445
+ getOpacity(): number;
1446
+ /**
1447
+ * 获取填充透明度
1448
+ */
1449
+ getFillOpacity(): number;
1450
+ /**
1451
+ * 获取描边透明度
1452
+ */
1453
+ getStrokeOpacity(): number;
1454
+ /**
1455
+ * 设置颜色(同时设置填充和描边)
1456
+ */
1457
+ color(value: string): Diagram;
1458
+ /**
1459
+ * 获取颜色(返回填充颜色,如果没有则返回描边颜色)
1460
+ */
1461
+ getColor(): string | undefined;
1462
+ /**
1463
+ * 复制样式自另一个 Diagram
1464
+ */
1465
+ matchStyle(other: Diagram): Diagram;
1466
+ /**
1467
+ * 获取样式对象的副本
1468
+ */
1469
+ getStyle(): Style;
1470
+ /** 平移 */
1471
+ translate(x: number, y: number): Diagram;
1472
+ translate(v: Vector2): Diagram;
1473
+ /** 移动到指定位置 */
1474
+ position(x: number, y: number): Diagram;
1475
+ position(v: Vector2): Diagram;
1476
+ /**
1477
+ * 移动图形(Manim 风格)
1478
+ *
1479
+ * 将图形中心移动到指定位置。与 position() 相同,
1480
+ * 但命名更符合 Manim 习惯。
1481
+ *
1482
+ * @example
1483
+ * ```typescript
1484
+ * import { square, Dir, mul } from 'locusing';
1485
+ *
1486
+ * // 移动到 (2, 3)
1487
+ * square(1).move([2, 3]);
1488
+ *
1489
+ * // 使用方向常量
1490
+ * square(1).move(mul(Dir.UP, 2)); // 向上移动 2 单位
1491
+ * square(1).move(mul(Dir.RIGHT, 3)); // 向右移动 3 单位
1492
+ *
1493
+ * // 组合方向
1494
+ * import { add } from 'locusing';
1495
+ * square(1).move(add(mul(Dir.UP, 2), mul(Dir.RIGHT, 3))); // 右上方
1496
+ * ```
1497
+ */
1498
+ move(x: number, y: number): Diagram;
1499
+ move(v: Vector2): Diagram;
1500
+ /**
1501
+ * 相对移动(偏移)
1502
+ *
1503
+ * 将图形从当前位置移动指定偏移量。
1504
+ *
1505
+ * @example
1506
+ * ```typescript
1507
+ * // 向右偏移 2 单位
1508
+ * square(1).shift([2, 0]);
1509
+ *
1510
+ * // 使用方向常量
1511
+ * square(1).shift(mul(Dir.UP, 1.5));
1512
+ * ```
1513
+ */
1514
+ shift(x: number, y: number): Diagram;
1515
+ shift(v: Vector2): Diagram;
1516
+ /** 旋转(弧度) */
1517
+ rotate(radians: number, center?: Vector2): Diagram;
1518
+ /** 旋转(度数) */
1519
+ rotateDeg(degrees: number, center?: Vector2): Diagram;
1520
+ /** 缩放 */
1521
+ scale(factor: number, center?: Vector2): Diagram;
1522
+ scale(sx: number, sy: number, center?: Vector2): Diagram;
1523
+ /** 应用变换矩阵 */
1524
+ transform(matrix: Matrix3): Diagram;
1525
+ /** 组合多个图形 */
1526
+ combine(...others: Diagram[]): Diagram;
1527
+ /** 添加子图形 */
1528
+ add(...others: Diagram[]): Diagram;
1529
+ /** 获取中心点 */
1530
+ center(): Vector2;
1531
+ /** Manim 风格别名:获取中心点 */
1532
+ getCenter(): Vector2;
1533
+ /** 获取包围盒 */
1534
+ bounds(): {
1535
+ x: number;
1536
+ y: number;
1537
+ width: number;
1538
+ height: number;
1539
+ };
1540
+ /** 获取宽度 */
1541
+ width(): number;
1542
+ /** Manim 风格别名:获取宽度 */
1543
+ getWidth(): number;
1544
+ /** 获取高度 */
1545
+ height(): number;
1546
+ /** Manim 风格别名:获取高度 */
1547
+ getHeight(): number;
1548
+ /** 获取左边缘 x 坐标 */
1549
+ getLeft(): number;
1550
+ /** 获取右边缘 x 坐标 */
1551
+ getRight(): number;
1552
+ /** 获取上边缘 y 坐标 */
1553
+ getTop(): number;
1554
+ /** 获取下边缘 y 坐标 */
1555
+ getBottom(): number;
1556
+ /** 获取左边缘点 */
1557
+ getLeftEdge(): Vector2;
1558
+ /** 获取右边缘点 */
1559
+ getRightEdge(): Vector2;
1560
+ /** 获取上边缘点 */
1561
+ getTopEdge(): Vector2;
1562
+ /** 获取下边缘点 */
1563
+ getBottomEdge(): Vector2;
1564
+ /** 获取指定方向的边缘点 */
1565
+ edge(direction: Vector2): Vector2;
1566
+ /**
1567
+ * 获取图形的所有点
1568
+ *
1569
+ * 对于路径图形返回路径点,对于基本图形返回边界框角点
1570
+ *
1571
+ * @example
1572
+ * ```typescript
1573
+ * const pts = polygon([0, 0], [1, 0], [0.5, 1]).getAllPoints();
1574
+ * // 返回多边形的顶点
1575
+ * ```
1576
+ */
1577
+ getAllPoints(): Vector2[];
1578
+ /**
1579
+ * 获取起始点
1580
+ *
1581
+ * 对于路径/多边形返回第一个顶点,其他图形返回左边缘点
1582
+ */
1583
+ getStart(): Vector2;
1584
+ /**
1585
+ * 获取结束点
1586
+ *
1587
+ * 对于路径/多边形返回最后一个顶点,其他图形返回右边缘点
1588
+ */
1589
+ getEnd(): Vector2;
1590
+ /**
1591
+ * 根据比例获取点
1592
+ *
1593
+ * @param proportion 0-1 之间的比例值
1594
+ * @returns 路径上对应比例位置的点
1595
+ *
1596
+ * @example
1597
+ * ```typescript
1598
+ * const line = polyline([0, 0], [4, 0]);
1599
+ * line.pointFromProportion(0.25) // 返回 [1, 0]
1600
+ * line.pointFromProportion(0.5) // 返回 [2, 0]
1601
+ * ```
1602
+ */
1603
+ pointFromProportion(proportion: number): Vector2;
1604
+ /**
1605
+ * 获取点的数量
1606
+ */
1607
+ getNumPoints(): number;
1608
+ /**
1609
+ * 检查是否有点
1610
+ */
1611
+ hasPoints(): boolean;
1612
+ /**
1613
+ * 获取关键点(角落点)
1614
+ */
1615
+ getCriticalPoints(): Vector2[];
1616
+ /**
1617
+ * 获取最左侧的点
1618
+ */
1619
+ getLeftmostPoint(): Vector2;
1620
+ /**
1621
+ * 获取最右侧的点
1622
+ */
1623
+ getRightmostPoint(): Vector2;
1624
+ /**
1625
+ * 获取最顶部的点
1626
+ */
1627
+ getTopmostPoint(): Vector2;
1628
+ /**
1629
+ * 获取最底部的点
1630
+ */
1631
+ getBottommostPoint(): Vector2;
1632
+ /**
1633
+ * 从 Shape 提取点
1634
+ * @internal
1635
+ */
1636
+ protected extractPoints(shape: Shape): Vector2[];
1637
+ /**
1638
+ * 相对定位 - 将图形放置在参考对象/点的指定方向
1639
+ *
1640
+ * @param target - 参考对象(Diagram)或参考点坐标(Vector2)
1641
+ * @param direction - 放置方向,使用 Dir.UP/DOWN/LEFT/RIGHT/UR/UL/DR/DL
1642
+ * @param buffer - 与参考对象的间距,默认 0.25
1643
+ *
1644
+ * @example
1645
+ * ```typescript
1646
+ * // 相对于另一个图形定位
1647
+ * label.nextTo(circle, Dir.RIGHT)
1648
+ *
1649
+ * // 相对于坐标点定位
1650
+ * label.nextTo([2, 0], Dir.RIGHT)
1651
+ *
1652
+ * // 带自定义间距
1653
+ * label.nextTo(axes.c2p(2, 0), Dir.UP, 0.1)
1654
+ * ```
1655
+ */
1656
+ nextTo(target: Diagram | Vector2, direction: Vector2, buffer?: number): Diagram;
1657
+ /**
1658
+ * 获取子对象列表
1659
+ *
1660
+ * Manim 风格:返回直接子对象的 Diagram 数组
1661
+ */
1662
+ get submobjects(): Diagram[];
1663
+ /**
1664
+ * 获取所有后代对象(包括自身)
1665
+ *
1666
+ * Manim 风格:递归获取所有子对象
1667
+ */
1668
+ getFamily(): Diagram[];
1669
+ /**
1670
+ * 获取所有后代对象(不包括自身)
1671
+ */
1672
+ getFamilyWithoutSelf(): Diagram[];
1673
+ /**
1674
+ * 按索引获取子对象
1675
+ */
1676
+ getSubmobjectAt(index: number): Diagram | undefined;
1677
+ /**
1678
+ * 获取子对象数量
1679
+ */
1680
+ get length(): number;
1681
+ /**
1682
+ * 对所有子对象应用变换
1683
+ */
1684
+ applyToFamily(fn: (diagram: Diagram) => Diagram): Diagram;
1685
+ /**
1686
+ * 将图形中心对齐到原点
1687
+ */
1688
+ centerOnOrigin(): Diagram;
1689
+ /**
1690
+ * 将图形对齐到另一个图形的指定边缘
1691
+ *
1692
+ * @param other - 参考图形
1693
+ * @param direction - 对齐方向
1694
+ */
1695
+ alignTo(other: Diagram, direction: Vector2): Diagram;
1696
+ /**
1697
+ * 排列子对象
1698
+ *
1699
+ * 将组内的子对象按指定方向排列成一行或一列
1700
+ *
1701
+ * @param direction - 排列方向,默认 [1, 0](水平向右)
1702
+ * @param buff - 子对象间距,默认 0.25
1703
+ *
1704
+ * @example
1705
+ * ```typescript
1706
+ * // 水平排列
1707
+ * group.arrange([1, 0]);
1708
+ *
1709
+ * // 垂直排列
1710
+ * group.arrange([0, 1]);
1711
+ *
1712
+ * // 使用方向常量
1713
+ * group.arrange(Dir.DOWN, 0.5);
1714
+ * ```
1715
+ */
1716
+ arrange(direction?: Vector2, buff?: number): Diagram;
1717
+ /**
1718
+ * 网格排列子对象
1719
+ *
1720
+ * @param rows - 行数
1721
+ * @param cols - 列数
1722
+ * @param options - 配置选项
1723
+ *
1724
+ * @example
1725
+ * ```typescript
1726
+ * // 3x3 网格
1727
+ * group.arrangeInGrid(3, 3);
1728
+ *
1729
+ * // 带间距配置
1730
+ * group.arrangeInGrid(2, 4, { buffX: 0.5, buffY: 0.3 });
1731
+ * ```
1732
+ */
1733
+ arrangeInGrid(rows: number, cols: number, options?: {
1734
+ buffX?: number;
1735
+ buffY?: number;
1736
+ cellWidth?: number;
1737
+ cellHeight?: number;
1738
+ }): Diagram;
1739
+ /**
1740
+ * 移动到角落
1741
+ *
1742
+ * @param corner - 角落方向,如 [1, 1] 表示右上角
1743
+ * @param buff - 与边缘的间距,默认 0.5
1744
+ *
1745
+ * @example
1746
+ * ```typescript
1747
+ * // 移动到右上角
1748
+ * diagram.toCorner([1, 1]);
1749
+ *
1750
+ * // 使用方向常量
1751
+ * diagram.toCorner(Dir.UL, 0.3);
1752
+ * ```
1753
+ */
1754
+ toCorner(corner: Vector2, buff?: number): Diagram;
1755
+ /**
1756
+ * 移动到边缘
1757
+ *
1758
+ * @param edge - 边缘方向,如 [1, 0] 表示右边缘
1759
+ * @param buff - 与边缘的间距,默认 0.5
1760
+ *
1761
+ * @example
1762
+ * ```typescript
1763
+ * // 移动到顶部边缘
1764
+ * diagram.toEdge([0, 1]);
1765
+ *
1766
+ * // 使用方向常量
1767
+ * diagram.toEdge(Dir.LEFT, 0.3);
1768
+ * ```
1769
+ */
1770
+ toEdge(edge: Vector2, buff?: number): Diagram;
1771
+ /**
1772
+ * 匹配另一个图形的宽度
1773
+ *
1774
+ * @param other - 参考图形
1775
+ *
1776
+ * @example
1777
+ * ```typescript
1778
+ * rect.matchWidth(circle);
1779
+ * ```
1780
+ */
1781
+ matchWidth(other: Diagram): Diagram;
1782
+ /**
1783
+ * 匹配另一个图形的高度
1784
+ *
1785
+ * @param other - 参考图形
1786
+ *
1787
+ * @example
1788
+ * ```typescript
1789
+ * rect.matchHeight(circle);
1790
+ * ```
1791
+ */
1792
+ matchHeight(other: Diagram): Diagram;
1793
+ /**
1794
+ * 环绕另一个图形
1795
+ *
1796
+ * 缩放并移动当前图形,使其恰好包围目标图形
1797
+ *
1798
+ * @param other - 要包围的目标图形
1799
+ * @param buff - 额外的边距,默认 0.1
1800
+ *
1801
+ * @example
1802
+ * ```typescript
1803
+ * // 用矩形框环绕文字
1804
+ * rect.surround(text, 0.2);
1805
+ * ```
1806
+ */
1807
+ surround(other: Diagram, buff?: number): Diagram;
1808
+ /** 克隆图形 */
1809
+ clone(): Diagram;
1810
+ /** 复制到指定位置 */
1811
+ copy(): Diagram;
1812
+ /**
1813
+ * 返回 AnimateProxy,用于 Manim 风格的动画语法
1814
+ *
1815
+ * @example
1816
+ * ```typescript
1817
+ * // 链式动画操作
1818
+ * await scene.play(circle.animate.shift([2, 0]).scale(2));
1819
+ *
1820
+ * // 带配置
1821
+ * await scene.play(circle.animate.runTime(2).shift([2, 0]));
1822
+ * ```
1823
+ */
1824
+ get animate(): AnimateProxy;
1825
+ /** 保存的状态栈 */
1826
+ private static stateStack;
1827
+ /**
1828
+ * 保存当前状态
1829
+ *
1830
+ * 将当前 Shape 状态压入栈中,可以稍后用 restore() 恢复
1831
+ *
1832
+ * @example
1833
+ * ```typescript
1834
+ * const c = circle(1).fill('red');
1835
+ * c.saveState();
1836
+ * const moved = c.shift([2, 0]).fill('blue');
1837
+ * // 稍后可以恢复
1838
+ * const restored = moved.restore(); // 恢复到 fill('red') 的状态
1839
+ * ```
1840
+ */
1841
+ saveState(): Diagram;
1842
+ /**
1843
+ * 恢复到保存的状态
1844
+ *
1845
+ * 从状态栈中弹出最近保存的状态并返回
1846
+ */
1847
+ restore(): Diagram;
1848
+ /**
1849
+ * 获取保存的状态(不移除)
1850
+ */
1851
+ getSavedState(): Diagram | undefined;
1852
+ /**
1853
+ * 生成目标副本
1854
+ *
1855
+ * 创建当前图形的副本,用于 MoveToTarget 动画
1856
+ *
1857
+ * @example
1858
+ * ```typescript
1859
+ * const c = circle(1);
1860
+ * c.generateTarget();
1861
+ * c.target = c.target.shift([2, 0]).scale(2);
1862
+ * await scene.play(MoveToTarget(c));
1863
+ * ```
1864
+ */
1865
+ generateTarget(): Diagram;
1866
+ /** 目标状态(用于 MoveToTarget) */
1867
+ target?: Diagram;
1868
+ /**
1869
+ * 替换为另一个 Diagram
1870
+ *
1871
+ * 返回一个与目标具有相同形状但保留原始 ID 的新 Diagram
1872
+ *
1873
+ * @example
1874
+ * ```typescript
1875
+ * const c = circle(1);
1876
+ * const s = square(1);
1877
+ * const newC = c.become(s); // 现在 newC 看起来像 square
1878
+ * ```
1879
+ */
1880
+ become(other: Diagram): Diagram;
1881
+ /**
1882
+ * 同时设置填充和描边颜色(Manim 风格)
1883
+ */
1884
+ setColor(color: string): Diagram;
1885
+ /**
1886
+ * 沿轴翻转
1887
+ *
1888
+ * @param axis - 翻转轴,默认 [1, 0](水平翻转)
1889
+ *
1890
+ * @example
1891
+ * ```typescript
1892
+ * // 水平翻转(沿 x 轴)
1893
+ * diagram.flip([1, 0]);
1894
+ *
1895
+ * // 垂直翻转(沿 y 轴)
1896
+ * diagram.flip([0, 1]);
1897
+ * ```
1898
+ */
1899
+ flip(axis?: Vector2): Diagram;
1900
+ /**
1901
+ * 单向拉伸
1902
+ *
1903
+ * @param factor - 拉伸因子
1904
+ * @param dimension - 拉伸维度:0 为 x 方向,1 为 y 方向
1905
+ *
1906
+ * @example
1907
+ * ```typescript
1908
+ * // 水平拉伸 2 倍
1909
+ * diagram.stretch(2, 0);
1910
+ *
1911
+ * // 垂直拉伸 0.5 倍
1912
+ * diagram.stretch(0.5, 1);
1913
+ * ```
1914
+ */
1915
+ stretch(factor: number, dimension: 0 | 1): Diagram;
1916
+ /**
1917
+ * 获取指定方向的角点
1918
+ *
1919
+ * @param direction - 方向向量,如 [1, 1] 表示右上角
1920
+ *
1921
+ * @example
1922
+ * ```typescript
1923
+ * // 获取右上角
1924
+ * diagram.getCorner([1, 1]);
1925
+ *
1926
+ * // 使用方向常量
1927
+ * diagram.getCorner(Dir.UR);
1928
+ * ```
1929
+ */
1930
+ getCorner(direction: Vector2): Vector2;
1931
+ /**
1932
+ * 获取指定方向的边缘中点
1933
+ *
1934
+ * @param direction - 方向向量
1935
+ */
1936
+ getEdgeCenter(direction: Vector2): Vector2;
1937
+ /**
1938
+ * 获取关键点(角点或边缘中点)
1939
+ *
1940
+ * @param direction - 方向向量
1941
+ */
1942
+ getCriticalPoint(direction: Vector2): Vector2;
1943
+ }
1944
+
1945
+ export { reflect as $, type Animation as A, dot as B, Camera as C, Diagram as D, type EasingFunction as E, type Frame as F, cross as G, length as H, type IndicateOptions as I, normalize as J, distance as K, LEFT as L, type MoveOptions as M, angle as N, ORIGIN as O, type PathCommand as P, angleBetween as Q, type RenderOptions as R, Scene as S, type TransformOptions as T, UP as U, type Vector2 as V, type WiggleOptions as W, rotate as X, lerp as Y, midpoint as Z, perpendicular as _, type CameraConfig as a, IDENTITY as a0, matrixMultiply as a1, applyMatrix as a2, translationMatrix as a3, rotationMatrix as a4, scaleMatrix as a5, quadraticBezier as a6, cubicBezier as a7, sampleParametric as a8, easing as a9, createCamera as aA, type RotateOptions as aB, type ScaleOptions as aC, ValueTracker as aD, ComplexValueTracker as aE, Timeline as aF, createTimeline as aG, getGSAPEasing as aH, easingMap as aI, type TimelineOptions as aJ, type AnimationStatus as aK, createScene as aL, type ScenePreset as aM, type UpdaterFunction as aN, type UpdaterConfig as aO, PI as aa, TAU as ab, DEGREES as ac, degToRad as ad, radToDeg as ae, clamp as af, mapRange as ag, lerpNumber as ah, type ShapeType as ai, type Shape as aj, type BaseShape as ak, type GroupShape as al, type PathShape as am, type RectShape as an, type CircleShape as ao, type EllipseShape as ap, type LineShape as aq, type PolylineShape as ar, type PolygonShape as as, type TextShape as at, type ArcShape as au, type TexShape as av, type FrameConfig as aw, type SliderOptions as ax, type LocatorOptions as ay, type AnimationOptions as az, type SceneConfig as b, type CreateOptions as c, type FadeOptions as d, type AnimationConfig as e, type CircumscribeOptions as f, type FlashOptions as g, type AnimationGroupOptions as h, type Style as i, type TextStyle as j, type Vector3 as k, type Point as l, type Matrix3 as m, V2 as n, V3 as o, DOWN as p, RIGHT as q, UL as r, UR as s, DL as t, DR as u, Dir as v, add as w, sub as x, mul as y, div as z };