s3m-three 0.3.7 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/anim/Animator.d.ts +111 -0
  2. package/dist/anim/Animator.d.ts.map +1 -0
  3. package/dist/anim/Animator.js +382 -0
  4. package/dist/anim/Animator.js.map +1 -0
  5. package/dist/anim/Path.d.ts +30 -0
  6. package/dist/anim/Path.d.ts.map +1 -0
  7. package/dist/anim/Path.js +100 -0
  8. package/dist/anim/Path.js.map +1 -0
  9. package/dist/anim/easing.d.ts +70 -0
  10. package/dist/anim/easing.d.ts.map +1 -0
  11. package/dist/anim/easing.js +170 -0
  12. package/dist/anim/easing.js.map +1 -0
  13. package/dist/anim/index.d.ts +6 -0
  14. package/dist/anim/index.d.ts.map +1 -0
  15. package/dist/anim/index.js +4 -0
  16. package/dist/anim/index.js.map +1 -0
  17. package/dist/browser/s3m-three.iife.ext-three.js +48 -10
  18. package/dist/browser/s3m-three.iife.js +48 -10
  19. package/dist/core/types.d.ts +16 -0
  20. package/dist/core/types.d.ts.map +1 -1
  21. package/dist/index.d.ts +3 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +1 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/render/EdgeLines.d.ts +62 -14
  26. package/dist/render/EdgeLines.d.ts.map +1 -1
  27. package/dist/render/EdgeLines.js +97 -8
  28. package/dist/render/EdgeLines.js.map +1 -1
  29. package/dist/render/FeatureStyleManager.d.ts +17 -1
  30. package/dist/render/FeatureStyleManager.d.ts.map +1 -1
  31. package/dist/render/FeatureStyleManager.js +14 -4
  32. package/dist/render/FeatureStyleManager.js.map +1 -1
  33. package/dist/render/MergeVertices.d.ts +7 -0
  34. package/dist/render/MergeVertices.d.ts.map +1 -1
  35. package/dist/render/MergeVertices.js +10 -1
  36. package/dist/render/MergeVertices.js.map +1 -1
  37. package/dist/render/S3MViewer.d.ts +216 -9
  38. package/dist/render/S3MViewer.d.ts.map +1 -1
  39. package/dist/render/S3MViewer.js +763 -67
  40. package/dist/render/S3MViewer.js.map +1 -1
  41. package/dist/render/StyleMaterial.d.ts +19 -0
  42. package/dist/render/StyleMaterial.d.ts.map +1 -1
  43. package/dist/render/StyleMaterial.js +37 -0
  44. package/dist/render/StyleMaterial.js.map +1 -1
  45. package/dist/tileset/S3MTileset.d.ts.map +1 -1
  46. package/dist/tileset/S3MTileset.js +3 -1
  47. package/dist/tileset/S3MTileset.js.map +1 -1
  48. package/docs/ANIMATION.md +534 -0
  49. package/docs/API.md +2 -0
  50. package/package.json +1 -1
  51. package/src/anim/Animator.ts +460 -0
  52. package/src/anim/Path.ts +107 -0
  53. package/src/anim/easing.ts +195 -0
  54. package/src/anim/index.ts +10 -0
  55. package/src/core/types.ts +8 -0
  56. package/src/index.ts +10 -0
  57. package/src/render/EdgeLines.ts +131 -15
  58. package/src/render/FeatureStyleManager.ts +12 -4
  59. package/src/render/MergeVertices.ts +11 -1
  60. package/src/render/S3MViewer.ts +855 -64
  61. package/src/render/StyleMaterial.ts +54 -1
  62. package/src/tileset/S3MTileset.ts +3 -1
@@ -0,0 +1,111 @@
1
+ /**
2
+ * 动画调度器
3
+ *
4
+ * 设计要点(详见 docs/ANIMATION.md):
5
+ *
6
+ * 1. **单一写者**:一帧内同一通道只由 tick() 写一次。公开 API 只写目标值,
7
+ * 渲染器永远不去猜「现在该显示什么」。
8
+ * 2. **同键合并**:Map<channelKey, Track>,重复调用只换目标、不叠队列。
9
+ * 3. **从当前值续走**:打断时起点取通道的**实际显示值**,不取逻辑终值,
10
+ * 所以连续调用不会跳回起点。
11
+ * 4. **空闲零成本**:没有 track 时 tick() 第一行就返回 false。
12
+ * 5. **预算可中断**:单帧写入超时就把剩下的留到下一帧——因为推进是按绝对
13
+ * 时间算的,跳一帧不丢状态,只是晚一帧显示。
14
+ *
15
+ * 不依赖 three / DOM:通道的读写由调用方注入,所以可以直接在 Node 里跑单测。
16
+ */
17
+ import { type EasingFn, type EasingName } from './easing.js';
18
+ /** 通道:把「某个属性」抽象成一段可读可写的浮点向量 */
19
+ export interface Channel {
20
+ /** 维度:1 = 标量(透明度 / 强度),3 = 向量(颜色 / 平移) */
21
+ readonly dim: 1 | 3;
22
+ /** 读当前显示值,写进 out[0..dim-1]。用于打断时取起点 */
23
+ read(out: Float32Array): void;
24
+ /** 写一帧的值。实现必须是 O(1) 且不分配——它会在每帧被调用 */
25
+ write(v: Float32Array): void;
26
+ }
27
+ export interface SpringSpec {
28
+ /** 刚度,越大越快(典型 80~300) */
29
+ stiffness: number;
30
+ /** 阻尼,越小越弹(典型 10~30;= 2√stiffness 为临界阻尼) */
31
+ damping: number;
32
+ /** 收敛阈值,位移与速度同时小于该值即判定结束 */
33
+ epsilon?: number;
34
+ }
35
+ export interface TransitionOptions {
36
+ /** 时长(毫秒)。0 / 不传 = 立即生效 */
37
+ duration?: number;
38
+ /** 延迟(毫秒) */
39
+ delay?: number;
40
+ /** 缓动曲线:内置名或自定义函数 */
41
+ easing?: EasingName | EasingFn;
42
+ /**
43
+ * 打断策略:
44
+ * - 'proportional'(默认)按剩余距离等比缩短时长,表现为恒速跟随
45
+ * - 'fixed' 每次都用完整时长
46
+ */
47
+ retarget?: 'proportional' | 'fixed';
48
+ /** 改用弹簧:有它就忽略 duration / easing */
49
+ spring?: SpringSpec;
50
+ /**
51
+ * 批量错峰间隔(毫秒)。只有 `animateFeatures` 这类批量接口会消费它:
52
+ * 一万个单体错峰 8ms,总时长不变,但每帧只动一小批,峰值天然摊平。
53
+ */
54
+ stagger?: number;
55
+ /** 本次动画结束(或被 finish)时回调 */
56
+ onComplete?: () => void;
57
+ }
58
+ export declare class Animator {
59
+ private readonly _channels;
60
+ private readonly _tracks;
61
+ private readonly _buf;
62
+ private readonly _finished;
63
+ private _now;
64
+ private _budgetMs;
65
+ /** 最近一次 tick 用的时间戳:新建 / 打断 track 时以它为下限,避免混用时钟导致起点落在过去 */
66
+ private _lastTick;
67
+ /** 上一帧因超预算被跳过的通道数(调试 / 降级判断用) */
68
+ private _skipped;
69
+ /**
70
+ * 有动画启动时的回调。
71
+ *
72
+ * 宿主渲染是**按需驱动**的:MapLibre 空闲时不渲染,只有 triggerRepaint 才画,
73
+ * 而 tick() 只在渲染帧里被调用——如果启动动画时不去踢一下帧循环,第一帧永远
74
+ * 等不来,动画就「卡住不动」,直到别的什么碰巧触发了重绘。
75
+ */
76
+ onActive?: () => void;
77
+ constructor(now?: () => number);
78
+ /** 单帧写入预算(毫秒)。超了就推到下一帧,保证不掉帧 */
79
+ set budgetMs(ms: number);
80
+ get budgetMs(): number;
81
+ /** 上一帧因超预算未写入的通道数 */
82
+ get skippedLastTick(): number;
83
+ get activeCount(): number;
84
+ get active(): boolean;
85
+ register(key: string, channel: Channel): void;
86
+ unregister(key: string): void;
87
+ /** 按前缀批量注销通道(场景清空时回收瓦片淡入这类「用完即弃」的通道) */
88
+ unregisterPrefix(prefix: string): void;
89
+ has(key: string): boolean;
90
+ isActive(key: string): boolean;
91
+ /**
92
+ * 把通道推向目标值。
93
+ *
94
+ * @param target 标量(dim=1)或三元数组(dim=3)
95
+ */
96
+ to(key: string, target: number | ArrayLike<number>, opts?: TransitionOptions): void;
97
+ /** 停在当前值:不写终值、不回弹 */
98
+ cancel(key: string): void;
99
+ /** 直接跳到终值并结束 */
100
+ finish(key: string): void;
101
+ /** 取消全部通道(切换数据集 / 卸载时用) */
102
+ clear(): void;
103
+ /**
104
+ * 推进一帧。
105
+ *
106
+ * @param now 当前时间(毫秒),不传则用构造时注入的时钟
107
+ * @returns 是否还有活跃动画(宿主据此决定要不要继续重绘)
108
+ */
109
+ tick(now?: number): boolean;
110
+ }
111
+ //# sourceMappingURL=Animator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Animator.d.ts","sourceRoot":"","sources":["../../src/anim/Animator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAU,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAErE,+BAA+B;AAC/B,MAAM,WAAW,OAAO;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IACpB,uCAAuC;IACvC,IAAI,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,sCAAsC;IACtC,KAAK,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,MAAM,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC;IACpC,mCAAmC;IACnC,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAoND,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IACxD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,SAAS,CAAO;IACxB,0DAA0D;IAC1D,OAAO,CAAC,SAAS,CAAa;IAC9B,iCAAiC;IACjC,OAAO,CAAC,QAAQ,CAAK;IACrB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;gBAEV,GAAG,GAAE,MAAM,MAAgC;IAIvD,gCAAgC;IAChC,IAAI,QAAQ,CAAC,EAAE,EAAE,MAAM,EAEtB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,qBAAqB;IACrB,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAI7C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAK7B,wCAAwC;IACxC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAStC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI9B;;;;OAIG;IACH,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,IAAI,GAAE,iBAAsB,GAAG,IAAI;IAsDvF,qBAAqB;IACrB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,gBAAgB;IAChB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IASzB,2BAA2B;IAC3B,KAAK,IAAI,IAAI;IAIb;;;;;OAKG;IACH,IAAI,CAAC,GAAG,GAAE,MAAoB,GAAG,OAAO;CA8BzC"}
@@ -0,0 +1,382 @@
1
+ /**
2
+ * 动画调度器
3
+ *
4
+ * 设计要点(详见 docs/ANIMATION.md):
5
+ *
6
+ * 1. **单一写者**:一帧内同一通道只由 tick() 写一次。公开 API 只写目标值,
7
+ * 渲染器永远不去猜「现在该显示什么」。
8
+ * 2. **同键合并**:Map<channelKey, Track>,重复调用只换目标、不叠队列。
9
+ * 3. **从当前值续走**:打断时起点取通道的**实际显示值**,不取逻辑终值,
10
+ * 所以连续调用不会跳回起点。
11
+ * 4. **空闲零成本**:没有 track 时 tick() 第一行就返回 false。
12
+ * 5. **预算可中断**:单帧写入超时就把剩下的留到下一帧——因为推进是按绝对
13
+ * 时间算的,跳一帧不丢状态,只是晚一帧显示。
14
+ *
15
+ * 不依赖 three / DOM:通道的读写由调用方注入,所以可以直接在 Node 里跑单测。
16
+ */
17
+ import { easing } from './easing.js';
18
+ const EPS = 1e-4;
19
+ const MIN_DURATION_RATIO = 0.15;
20
+ function clamp01(v) {
21
+ return v < 0 ? 0 : v > 1 ? 1 : v;
22
+ }
23
+ /** 两个向量的最大分量距离,用来算「剩余距离 / 总距离」 */
24
+ function maxDist(a, b, dim) {
25
+ let m = 0;
26
+ for (let i = 0; i < dim; i++) {
27
+ const d = Math.abs(a[i] - b[i]);
28
+ if (d > m)
29
+ m = d;
30
+ }
31
+ return m;
32
+ }
33
+ /* ------------------------------------------------------------------ Track */
34
+ class Track {
35
+ key;
36
+ channel;
37
+ dim;
38
+ to = new Float32Array(3);
39
+ _cur = new Float32Array(3);
40
+ done = false;
41
+ onComplete;
42
+ constructor(key, channel) {
43
+ this.key = key;
44
+ this.channel = channel;
45
+ this.dim = channel.dim;
46
+ }
47
+ }
48
+ /** 时间驱动的补间:from → to,按缓动曲线映射进度 */
49
+ class TweenTrack extends Track {
50
+ _from = new Float32Array(3);
51
+ _start = 0;
52
+ _duration = 0;
53
+ _delay = 0;
54
+ _ease = easing('linear');
55
+ _retarget = 'proportional';
56
+ /** 本次补间的原始总距离,用来做等比缩时长 */
57
+ _span = 0;
58
+ _progress = 0;
59
+ get progress() {
60
+ return this._progress;
61
+ }
62
+ start(now, opts, from) {
63
+ if (from)
64
+ this._from.set(from.subarray(0, this.dim));
65
+ else
66
+ this.channel.read(this._from);
67
+ this._start = now;
68
+ this._delay = Math.max(0, opts.delay ?? 0);
69
+ this._duration = Math.max(0, opts.duration ?? 0);
70
+ this._ease = opts.easing ? easing(opts.easing) : easing('linear');
71
+ this._retarget = opts.retarget ?? 'proportional';
72
+ this._span = maxDist(this._from, this.to, this.dim);
73
+ this._progress = 0;
74
+ this.done = false;
75
+ }
76
+ advance(now) {
77
+ const elapsed = now - this._start - this._delay;
78
+ const t = this._duration <= 0 ? 1 : clamp01(elapsed / this._duration);
79
+ this._progress = t;
80
+ const k = this._ease(t);
81
+ for (let i = 0; i < this.dim; i++) {
82
+ this._cur[i] = this._from[i] + (this.to[i] - this._from[i]) * k;
83
+ }
84
+ this.channel.write(this._cur);
85
+ if (t >= 1)
86
+ this.done = true;
87
+ }
88
+ retarget(to, now, opts) {
89
+ // 起点取通道实际显示值——这是「不跳回起点」的关键
90
+ this.channel.read(this._from);
91
+ this.to.set(to.subarray(0, this.dim));
92
+ const base = Math.max(0, opts.duration ?? this._duration);
93
+ let duration = base;
94
+ if ((opts.retarget ?? this._retarget) !== 'fixed' && this._span > EPS) {
95
+ const remain = maxDist(this._from, this.to, this.dim);
96
+ const ratio = remain / this._span;
97
+ duration = Math.min(base, Math.max(base * MIN_DURATION_RATIO, base * ratio));
98
+ }
99
+ this._start = now;
100
+ this._delay = Math.max(0, opts.delay ?? 0);
101
+ this._duration = duration;
102
+ this._ease = opts.easing ? easing(opts.easing) : this._ease;
103
+ this._span = maxDist(this._from, this.to, this.dim);
104
+ this._progress = 0;
105
+ this.done = false;
106
+ }
107
+ }
108
+ /**
109
+ * 弹簧:没有时长概念,靠物理收敛。
110
+ *
111
+ * 用**解析解**而不是逐帧欧拉积分:帧率抖动、切标签页回来、单帧 dt 很大,
112
+ * 结果都一样,且不累积误差。中断时只换 target,位置和速度天然连续。
113
+ */
114
+ class SpringTrack extends Track {
115
+ _x0 = new Float32Array(3);
116
+ _v0 = new Float32Array(3);
117
+ _vel = new Float32Array(3);
118
+ _start = 0;
119
+ _k = 120;
120
+ _c = 14;
121
+ _eps = 1e-3;
122
+ _progress = 0;
123
+ get progress() {
124
+ // 弹簧没有天然进度,用「距离收敛比例」近似,仅用于调试展示
125
+ return this._progress;
126
+ }
127
+ start(now, opts, from) {
128
+ const sp = opts.spring ?? { stiffness: 120, damping: 14 };
129
+ this._k = Math.max(1e-3, sp.stiffness);
130
+ this._c = Math.max(0, sp.damping);
131
+ this._eps = sp.epsilon ?? 1e-3;
132
+ if (from)
133
+ this._x0.set(from.subarray(0, this.dim));
134
+ else
135
+ this.channel.read(this._x0);
136
+ this._v0.fill(0);
137
+ this._vel.fill(0);
138
+ this._start = now;
139
+ this.done = false;
140
+ this._progress = 0;
141
+ }
142
+ advance(now) {
143
+ const t = Math.max(0, (now - this._start) / 1000);
144
+ let settled = true;
145
+ for (let i = 0; i < this.dim; i++) {
146
+ const { x, v } = springAt(this._x0[i] - this.to[i], this._v0[i], this._k, this._c, t);
147
+ this._cur[i] = this.to[i] + x;
148
+ this._vel[i] = v;
149
+ if (Math.abs(x) > this._eps || Math.abs(v) > this._eps)
150
+ settled = false;
151
+ }
152
+ this.channel.write(this._cur);
153
+ if (settled) {
154
+ for (let i = 0; i < this.dim; i++)
155
+ this._cur[i] = this.to[i];
156
+ this.channel.write(this._cur);
157
+ this.done = true;
158
+ this._progress = 1;
159
+ }
160
+ }
161
+ retarget(to, now, opts) {
162
+ // 把当前位置与速度搬成新的初始条件:速度不清零,所以不会顿一下
163
+ this.channel.read(this._cur);
164
+ const sp = opts.spring;
165
+ if (sp) {
166
+ this._k = Math.max(1e-3, sp.stiffness);
167
+ this._c = Math.max(0, sp.damping);
168
+ this._eps = sp.epsilon ?? this._eps;
169
+ }
170
+ const t = Math.max(0, (now - this._start) / 1000);
171
+ for (let i = 0; i < this.dim; i++) {
172
+ const s = springAt(this._x0[i] - this.to[i], this._v0[i], this._k, this._c, t);
173
+ this._x0[i] = this._cur[i] - to[i];
174
+ this._v0[i] = s.v;
175
+ }
176
+ this.to.set(to.subarray(0, this.dim));
177
+ this._start = now;
178
+ this.done = false;
179
+ }
180
+ }
181
+ /**
182
+ * 阻尼弹簧解析解(质量 = 1)。
183
+ * @param x0 初始位移(相对目标)
184
+ * @param v0 初始速度
185
+ */
186
+ function springAt(x0, v0, k, c, t) {
187
+ const w0 = Math.sqrt(k);
188
+ const zeta = c / (2 * w0);
189
+ if (zeta < 1) {
190
+ const wd = w0 * Math.sqrt(1 - zeta * zeta);
191
+ const decay = Math.exp(-zeta * w0 * t);
192
+ const cos = Math.cos(wd * t);
193
+ const sin = Math.sin(wd * t);
194
+ const A = x0;
195
+ const B = (v0 + zeta * w0 * x0) / wd;
196
+ return {
197
+ x: decay * (A * cos + B * sin),
198
+ v: decay * ((B * wd - zeta * w0 * A) * cos + (-A * wd - zeta * w0 * B) * sin),
199
+ };
200
+ }
201
+ // 临界 / 过阻尼:用临界解近似(过阻尼不会振荡,视觉差异可忽略)
202
+ const decay = Math.exp(-w0 * t);
203
+ const C = v0 + w0 * x0;
204
+ return {
205
+ x: (x0 + C * t) * decay,
206
+ v: (v0 - w0 * C * t) * decay,
207
+ };
208
+ }
209
+ /* ------------------------------------------------------------------ Animator */
210
+ export class Animator {
211
+ _channels = new Map();
212
+ _tracks = new Map();
213
+ _buf = new Float32Array(3);
214
+ _finished = [];
215
+ _now;
216
+ _budgetMs = 2.5;
217
+ /** 最近一次 tick 用的时间戳:新建 / 打断 track 时以它为下限,避免混用时钟导致起点落在过去 */
218
+ _lastTick = -Infinity;
219
+ /** 上一帧因超预算被跳过的通道数(调试 / 降级判断用) */
220
+ _skipped = 0;
221
+ /**
222
+ * 有动画启动时的回调。
223
+ *
224
+ * 宿主渲染是**按需驱动**的:MapLibre 空闲时不渲染,只有 triggerRepaint 才画,
225
+ * 而 tick() 只在渲染帧里被调用——如果启动动画时不去踢一下帧循环,第一帧永远
226
+ * 等不来,动画就「卡住不动」,直到别的什么碰巧触发了重绘。
227
+ */
228
+ onActive;
229
+ constructor(now = () => performance.now()) {
230
+ this._now = now;
231
+ }
232
+ /** 单帧写入预算(毫秒)。超了就推到下一帧,保证不掉帧 */
233
+ set budgetMs(ms) {
234
+ this._budgetMs = Math.max(0, ms);
235
+ }
236
+ get budgetMs() {
237
+ return this._budgetMs;
238
+ }
239
+ /** 上一帧因超预算未写入的通道数 */
240
+ get skippedLastTick() {
241
+ return this._skipped;
242
+ }
243
+ get activeCount() {
244
+ return this._tracks.size;
245
+ }
246
+ get active() {
247
+ return this._tracks.size > 0;
248
+ }
249
+ register(key, channel) {
250
+ this._channels.set(key, channel);
251
+ }
252
+ unregister(key) {
253
+ this._channels.delete(key);
254
+ this._tracks.delete(key);
255
+ }
256
+ /** 按前缀批量注销通道(场景清空时回收瓦片淡入这类「用完即弃」的通道) */
257
+ unregisterPrefix(prefix) {
258
+ for (const key of [...this._channels.keys()]) {
259
+ if (key.startsWith(prefix)) {
260
+ this._channels.delete(key);
261
+ this._tracks.delete(key);
262
+ }
263
+ }
264
+ }
265
+ has(key) {
266
+ return this._channels.has(key);
267
+ }
268
+ isActive(key) {
269
+ return this._tracks.has(key);
270
+ }
271
+ /**
272
+ * 把通道推向目标值。
273
+ *
274
+ * @param target 标量(dim=1)或三元数组(dim=3)
275
+ */
276
+ to(key, target, opts = {}) {
277
+ const channel = this._channels.get(key);
278
+ if (!channel)
279
+ throw new Error(`[s3m] 未注册的动画通道: ${key}`);
280
+ const to = this._buf;
281
+ if (channel.dim === 1) {
282
+ to[0] = typeof target === 'number' ? target : Number(target[0]);
283
+ to[1] = 0;
284
+ to[2] = 0;
285
+ }
286
+ else {
287
+ if (typeof target === 'number')
288
+ throw new Error(`[s3m] 通道 ${key} 需要三元数组目标值`);
289
+ for (let i = 0; i < 3; i++)
290
+ to[i] = Number(target[i] ?? 0);
291
+ }
292
+ const isSpring = !!opts.spring;
293
+ const duration = Math.max(0, opts.duration ?? 0);
294
+ // 无时长、无弹簧 → 立即写,不建 track(保持旧行为)
295
+ if (!isSpring && duration <= 0 && !opts.delay) {
296
+ this._tracks.delete(key);
297
+ channel.write(to);
298
+ // 值变了就得重画,否则按需驱动的宿主看不到
299
+ this.onActive?.();
300
+ opts.onComplete?.();
301
+ return;
302
+ }
303
+ const now = Math.max(this._now(), this._lastTick);
304
+ let track = this._tracks.get(key);
305
+ const wantSpring = isSpring;
306
+ const isSpringTrack = track instanceof SpringTrack;
307
+ const kindChanged = track != null && isSpringTrack !== wantSpring;
308
+ if (track && kindChanged) {
309
+ this._tracks.delete(key);
310
+ track = undefined;
311
+ }
312
+ // 新建 track = 动画真正启动,必须把空闲的帧循环踢起来,否则第一帧等不来
313
+ if (!track)
314
+ this.onActive?.();
315
+ if (!track) {
316
+ const created = wantSpring ? new SpringTrack(key, channel) : new TweenTrack(key, channel);
317
+ created.to.set(to.subarray(0, channel.dim));
318
+ created.onComplete = opts.onComplete;
319
+ created.start(now, opts);
320
+ this._tracks.set(key, created);
321
+ return;
322
+ }
323
+ track.to.set(to.subarray(0, channel.dim));
324
+ track.onComplete = opts.onComplete;
325
+ track.retarget(to, now, opts);
326
+ }
327
+ /** 停在当前值:不写终值、不回弹 */
328
+ cancel(key) {
329
+ this._tracks.delete(key);
330
+ }
331
+ /** 直接跳到终值并结束 */
332
+ finish(key) {
333
+ const track = this._tracks.get(key);
334
+ if (!track)
335
+ return;
336
+ this._tracks.delete(key);
337
+ track.channel.write(track.to);
338
+ this.onActive?.();
339
+ track.onComplete?.();
340
+ }
341
+ /** 取消全部通道(切换数据集 / 卸载时用) */
342
+ clear() {
343
+ this._tracks.clear();
344
+ }
345
+ /**
346
+ * 推进一帧。
347
+ *
348
+ * @param now 当前时间(毫秒),不传则用构造时注入的时钟
349
+ * @returns 是否还有活跃动画(宿主据此决定要不要继续重绘)
350
+ */
351
+ tick(now = this._now()) {
352
+ if (this._tracks.size === 0) {
353
+ this._lastTick = Math.max(this._lastTick, now);
354
+ return false;
355
+ }
356
+ this._lastTick = Math.max(this._lastTick, now);
357
+ const startedAt = performance.now();
358
+ let advanced = 0;
359
+ for (const track of this._tracks.values()) {
360
+ track.advance(now);
361
+ advanced++;
362
+ if (track.done)
363
+ this._finished.push(track);
364
+ // 预算用完:剩下的留到下一帧(推进按绝对时间算,跳一帧不丢状态)
365
+ if (performance.now() - startedAt >= this._budgetMs)
366
+ break;
367
+ }
368
+ if (this._finished.length > 0) {
369
+ for (const track of this._finished) {
370
+ if (this._tracks.get(track.key) === track)
371
+ this._tracks.delete(track.key);
372
+ }
373
+ // 回调里可能再起新动画,所以先摘出来再执行
374
+ const list = this._finished.splice(0, this._finished.length);
375
+ for (const track of list)
376
+ track.onComplete?.();
377
+ }
378
+ this._skipped = Math.max(0, this._tracks.size - advanced);
379
+ return this._tracks.size > 0;
380
+ }
381
+ }
382
+ //# sourceMappingURL=Animator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Animator.js","sourceRoot":"","sources":["../../src/anim/Animator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 折线路径(弧长参数化)
3
+ *
4
+ * 为什么不能直接对顶点做插值:顶点疏密不均时,`lerp(p[i], p[i+1], t)` 的速度
5
+ * 取决于顶点间距——顶点密的地方走得慢、疏的地方一下窜过去。所以先把折线展开成
6
+ * **累计弧长表**,运动时按「已走距离 s」反解位置,缓动作用在距离上而不是顶点索引上。
7
+ *
8
+ * 纯数学,不依赖 three,可以单独测。
9
+ */
10
+ export declare class Path {
11
+ /** 扁平坐标 xyz */
12
+ private readonly _pts;
13
+ /** 每个顶点处的累计弧长,长度与顶点数相同 */
14
+ private readonly _cum;
15
+ /** 总弧长(米) */
16
+ readonly length: number;
17
+ constructor(points: ArrayLike<number> | Array<[number, number, number]>, opts?: {
18
+ closed?: boolean;
19
+ });
20
+ /**
21
+ * 取弧长 s 处的位置。
22
+ * @param s 已走距离(米),会被夹到 [0, length]
23
+ * @param out 结果写入这里(长度 ≥ 3 的数组)
24
+ */
25
+ sample(s: number, out: Float32Array | number[]): void;
26
+ /** 按归一化进度取位置(0 → 起点,1 → 终点) */
27
+ sampleAt(t: number, out: Float32Array | number[]): void;
28
+ private static _flatten;
29
+ }
30
+ //# sourceMappingURL=Path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Path.d.ts","sourceRoot":"","sources":["../../src/anim/Path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,qBAAa,IAAI;IACf,eAAe;IACf,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,0BAA0B;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,aAAa;IACb,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAO;IA8BxG;;;;OAIG;IACH,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI;IAgCrD,+BAA+B;IAC/B,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI;IAIvD,OAAO,CAAC,MAAM,CAAC,QAAQ;CAiBxB"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * 折线路径(弧长参数化)
3
+ *
4
+ * 为什么不能直接对顶点做插值:顶点疏密不均时,`lerp(p[i], p[i+1], t)` 的速度
5
+ * 取决于顶点间距——顶点密的地方走得慢、疏的地方一下窜过去。所以先把折线展开成
6
+ * **累计弧长表**,运动时按「已走距离 s」反解位置,缓动作用在距离上而不是顶点索引上。
7
+ *
8
+ * 纯数学,不依赖 three,可以单独测。
9
+ */
10
+ export class Path {
11
+ /** 扁平坐标 xyz */
12
+ _pts;
13
+ /** 每个顶点处的累计弧长,长度与顶点数相同 */
14
+ _cum;
15
+ /** 总弧长(米) */
16
+ length;
17
+ constructor(points, opts = {}) {
18
+ const flat = Path._flatten(points);
19
+ const closed = opts.closed === true && flat.length >= 9;
20
+ const count = flat.length / 3;
21
+ const n = closed ? count + 1 : count;
22
+ this._pts = new Float32Array(n * 3);
23
+ this._pts.set(flat);
24
+ if (closed) {
25
+ // 闭合路径:末尾补回起点,走完一圈刚好回到原处
26
+ this._pts[n * 3 - 3] = flat[0];
27
+ this._pts[n * 3 - 2] = flat[1];
28
+ this._pts[n * 3 - 1] = flat[2];
29
+ }
30
+ this._cum = new Float32Array(Math.max(n, 1));
31
+ let total = 0;
32
+ for (let i = 1; i < n; i++) {
33
+ const a = (i - 1) * 3;
34
+ const b = i * 3;
35
+ total += Math.hypot(this._pts[b] - this._pts[a], this._pts[b + 1] - this._pts[a + 1], this._pts[b + 2] - this._pts[a + 2]);
36
+ this._cum[i] = total;
37
+ }
38
+ this.length = total;
39
+ }
40
+ /**
41
+ * 取弧长 s 处的位置。
42
+ * @param s 已走距离(米),会被夹到 [0, length]
43
+ * @param out 结果写入这里(长度 ≥ 3 的数组)
44
+ */
45
+ sample(s, out) {
46
+ const n = this._pts.length / 3;
47
+ if (n === 0) {
48
+ out[0] = out[1] = out[2] = 0;
49
+ return;
50
+ }
51
+ if (n === 1 || this.length <= 0) {
52
+ out[0] = this._pts[0];
53
+ out[1] = this._pts[1];
54
+ out[2] = this._pts[2];
55
+ return;
56
+ }
57
+ const d = Math.min(this.length, Math.max(0, s));
58
+ // 二分查段:cum[i] <= d <= cum[i+1]
59
+ let lo = 0;
60
+ let hi = n - 1;
61
+ while (hi - lo > 1) {
62
+ const mid = (lo + hi) >> 1;
63
+ if (this._cum[mid] <= d)
64
+ lo = mid;
65
+ else
66
+ hi = mid;
67
+ }
68
+ const segLen = this._cum[hi] - this._cum[lo];
69
+ const k = segLen > 0 ? (d - this._cum[lo]) / segLen : 0;
70
+ const a = lo * 3;
71
+ const b = hi * 3;
72
+ out[0] = this._pts[a] + (this._pts[b] - this._pts[a]) * k;
73
+ out[1] = this._pts[a + 1] + (this._pts[b + 1] - this._pts[a + 1]) * k;
74
+ out[2] = this._pts[a + 2] + (this._pts[b + 2] - this._pts[a + 2]) * k;
75
+ }
76
+ /** 按归一化进度取位置(0 → 起点,1 → 终点) */
77
+ sampleAt(t, out) {
78
+ this.sample(Math.min(1, Math.max(0, t)) * this.length, out);
79
+ }
80
+ static _flatten(points) {
81
+ if (points.length === 0)
82
+ return new Float32Array(0);
83
+ // 扁平数组:[x,y,z, x,y,z, ...]
84
+ if (typeof points[0] === 'number') {
85
+ const arr = points;
86
+ if (arr.length % 3 !== 0)
87
+ throw new Error('[s3m] 路径点数组长度必须是 3 的倍数');
88
+ return Float32Array.from(arr);
89
+ }
90
+ const tuples = points;
91
+ const out = new Float32Array(tuples.length * 3);
92
+ for (let i = 0; i < tuples.length; i++) {
93
+ out[i * 3] = tuples[i][0];
94
+ out[i * 3 + 1] = tuples[i][1];
95
+ out[i * 3 + 2] = tuples[i][2];
96
+ }
97
+ return out;
98
+ }
99
+ }
100
+ //# sourceMappingURL=Path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Path.js","sourceRoot":"","sources":["../../src/anim/Path.ts"],"names":[],"mappings":"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"}