dsh-notch 0.3.1 → 0.3.6

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 (102) hide show
  1. package/README.en.md +58 -47
  2. package/README.md +60 -55
  3. package/cordis.patch.yml +3 -0
  4. package/desktop/README.md +29 -0
  5. package/desktop/notch-lifecycle.mjs +120 -0
  6. package/desktop/restart-probe.mjs +61 -0
  7. package/docs/desktop-017rc2.md +23 -0
  8. package/docs/elastic-edge-dock.md +127 -0
  9. package/docs/motion-audit.md +1 -1
  10. package/docs/releases/v0.3.2.md +38 -0
  11. package/docs/releases/v0.3.3.md +9 -0
  12. package/docs/subagent-compatibility.md +51 -0
  13. package/docs/verification/elastic-algorithm-timing.json +337 -0
  14. package/docs/verification/elastic-attention.json +44 -0
  15. package/docs/verification/elastic-frame-timing.json +240 -0
  16. package/docs/verification/elastic-tension.json +59 -0
  17. package/docs/verification/elastic-tip-taper.json +181 -0
  18. package/dshx.yml +2 -0
  19. package/lib/client.js +112 -0
  20. package/lib/client.js.map +1 -0
  21. package/lib/index.mjs +990 -0
  22. package/lib/index.mjs.map +1 -0
  23. package/package.json +66 -10
  24. package/src/board.ts +178 -35
  25. package/src/client/index.ts +104 -0
  26. package/src/dsh-notch.ts +19 -2
  27. package/src/http.ts +17 -2
  28. package/src/session-state.ts +15 -1
  29. package/src/store.ts +3 -3
  30. package/src/types.ts +3 -0
  31. package/BASELINE.md +0 -13
  32. package/DESIGN.md +0 -34
  33. package/cordis.yml +0 -5
  34. package/macos/Package.swift +0 -17
  35. package/macos/STATUS-MOTION.md +0 -49
  36. package/macos/Sources/Client.swift +0 -139
  37. package/macos/Sources/IdleRobot.swift +0 -423
  38. package/macos/Sources/NotchMarkdown.swift +0 -266
  39. package/macos/Sources/Panel.swift +0 -153
  40. package/macos/Sources/Resources/Idle/balance.json +0 -1
  41. package/macos/Sources/Resources/Idle/blink.json +0 -1
  42. package/macos/Sources/Resources/Idle/cube-in.json +0 -1
  43. package/macos/Sources/Resources/Idle/dance.json +0 -1
  44. package/macos/Sources/Resources/Idle/hop.json +0 -1
  45. package/macos/Sources/Resources/Idle/nod.json +0 -1
  46. package/macos/Sources/Resources/Idle/satellite-in.json +0 -1
  47. package/macos/Sources/Resources/Idle/satellite-out.json +0 -1
  48. package/macos/Sources/Resources/Idle/scan.json +0 -1
  49. package/macos/Sources/Resources/Idle/sleep.json +0 -1
  50. package/macos/Sources/Resources/Idle/sneeze.json +0 -1
  51. package/macos/Sources/Resources/Idle/stretch.json +0 -1
  52. package/macos/Sources/Resources/Idle/tilt.json +0 -1
  53. package/macos/Sources/ReviewStudio.swift +0 -337
  54. package/macos/Sources/RootView.swift +0 -1093
  55. package/macos/Sources/StatusOrbit.swift +0 -642
  56. package/macos/Sources/main.swift +0 -153
  57. package/macos/Tests/ExpandedHeightProbe.swift +0 -108
  58. package/macos/Tests/GeometryProbe.swift +0 -98
  59. package/macos/Tests/IdleProbe.swift +0 -294
  60. package/macos/Tests/MotionProbe.swift +0 -106
  61. package/macos/Tests/OutcomeProbe.swift +0 -133
  62. package/macos/Tests/ScrollbarProbe.swift +0 -91
  63. package/macos/Tests/expanded-height.sh +0 -13
  64. package/macos/Tests/geometry.sh +0 -14
  65. package/macos/Tests/idle.sh +0 -14
  66. package/macos/Tests/motion.sh +0 -14
  67. package/macos/Tests/outcome.sh +0 -14
  68. package/macos/Tests/scrollbar.sh +0 -13
  69. package/tests/answer-lifecycle.test.mjs +0 -23
  70. package/tests/board.test.mjs +0 -7
  71. package/tests/browse-sync.test.mjs +0 -20
  72. package/tests/mirror.test.mjs +0 -4
  73. package/tests/peer-range.test.mjs +0 -21
  74. package/tests/session-state.test.mjs +0 -54
  75. package/tests/unread-hold.test.mjs +0 -90
  76. package/tools/desktop-shell/README.md +0 -56
  77. package/tools/desktop-shell/child-log.mjs +0 -6
  78. package/tools/desktop-shell/child-log.test.mjs +0 -14
  79. package/tools/desktop-shell/package-recovery.py +0 -78
  80. package/tools/desktop-shell/recovery-probe.cjs +0 -50
  81. package/tools/desktop-shell/renderer-recovery.mjs +0 -95
  82. package/tools/desktop-shell/renderer-recovery.test.mjs +0 -24
  83. package/tools/diagnostics/completion-watch.py +0 -101
  84. package/tools/diagnostics/completion-watch.test.py +0 -17
  85. package/tools/diagnostics/renderer-diagnostics.mjs +0 -56
  86. package/tools/diagnostics/renderer-diagnostics.test.mjs +0 -32
  87. package/tools/idle/LICENSE.open-bot-motion +0 -21
  88. package/tools/idle/export.mjs +0 -40
  89. package/tools/idle/index.html +0 -4
  90. package/tools/idle/motions.js +0 -83
  91. package/tools/idle/original.js +0 -1673
  92. package/tools/idle/renderer.js +0 -1673
  93. package/tools/recording/Client.swift +0 -76
  94. package/tools/recording/DemoCatalog.swift +0 -174
  95. package/tools/recording/README.md +0 -23
  96. package/tools/recording/build.sh +0 -41
  97. package/tools/recording/main.swift +0 -100
  98. package/tools/review/ReviewStudio.swift +0 -236
  99. package/tools/review/audit.sh +0 -19
  100. package/tools/review/build.sh +0 -7
  101. package/tools/review/main.swift +0 -158
  102. package/tools/review/render-audit.swift +0 -32
@@ -1,1673 +0,0 @@
1
- /**
2
- * OpenBotMotion v1.0.0
3
- * Pure Code-Driven Zero-Dependency SVG Mascot Animation Engine (#1 ~ #7)
4
- *
5
- * @license MIT
6
- * @author Open Bot Motion Team
7
- */
8
-
9
- (function (root, factory) {
10
- if (typeof define === 'function' && define.amd) {
11
- define([], factory);
12
- } else if (typeof module === 'object' && module.exports) {
13
- module.exports = factory();
14
- } else {
15
- root.OpenBotMotion = factory();
16
- }
17
- }(typeof self !== 'undefined' ? self : this, function () {
18
- 'use strict';
19
-
20
- var CHARCOAL = '#222126';
21
- var EYE = '#ffffff';
22
- var LOOP = 20.783;
23
-
24
- /* =========================================================================
25
- 1. Motion Primitives & Math
26
- ========================================================================= */
27
- var Easings = {
28
- linear: function (p) { return p; },
29
- easeInOutQuad: function (p) {
30
- return p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2;
31
- },
32
- easeOutCubic: function (p) {
33
- return 1 - Math.pow(1 - p, 3);
34
- },
35
- easeInCubic: function (p) {
36
- return p * p * p;
37
- },
38
- easeInOutCubic: function (p) {
39
- return p < 0.5 ? 4 * p * p * p : 1 - Math.pow(-2 * p + 2, 3) / 2;
40
- },
41
- springBouncy: function (p) {
42
- if (p <= 0) return 0;
43
- if (p >= 1) return 1;
44
- var c4 = (2 * Math.PI) / 3;
45
- return Math.pow(2, -10 * p) * Math.sin((p * 10 - 0.75) * c4) + 1;
46
- }
47
- };
48
-
49
- function clamp(v, a, b) { return Math.max(a, Math.min(b, v)); }
50
- function lerp(a, b, t) { return a + (b - a) * t; }
51
-
52
- function PoseTimeline(keyframes, options) {
53
- this.options = Object.assign({
54
- shortestArc: true,
55
- shortestArcAngles: ['yaw', 'pitch', 'roll']
56
- }, options || {});
57
-
58
- var self = this;
59
- this.keyframes = keyframes.map(function (kf) {
60
- return {
61
- t: kf.t,
62
- label: kf.label || '',
63
- ease: kf.ease || 'easeInOutQuad',
64
- shortestArc: kf.shortestArc !== undefined ? kf.shortestArc : self.options.shortestArc,
65
- pose: Object.assign({}, kf.pose)
66
- };
67
- }).sort(function (a, b) { return a.t - b.t; });
68
-
69
- if (this.options.shortestArc) {
70
- var angleKeys = this.options.shortestArcAngles;
71
- for (var k = 0; k < angleKeys.length; k++) {
72
- var key = angleKeys[k];
73
- var prevVal = null;
74
- for (var i = 0; i < this.keyframes.length; i++) {
75
- var kf = this.keyframes[i];
76
- if (kf.pose && typeof kf.pose[key] === 'number') {
77
- if (prevVal !== null && kf.shortestArc !== false) {
78
- var diff = kf.pose[key] - prevVal;
79
- if (Math.abs(Math.abs(diff) - Math.PI) > 1e-4) {
80
- var shortDiff = ((diff + Math.PI) % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI) - Math.PI;
81
- kf.pose[key] = prevVal + shortDiff;
82
- }
83
- }
84
- prevVal = kf.pose[key];
85
- }
86
- }
87
- }
88
- }
89
- }
90
-
91
- PoseTimeline.prototype.evaluate = function (t) {
92
- var kfs = this.keyframes;
93
- if (t <= kfs[0].t) {
94
- return { pose: Object.assign({}, kfs[0].pose), label: kfs[0].label || '' };
95
- }
96
- if (t >= kfs[kfs.length - 1].t) {
97
- var last = kfs[kfs.length - 1];
98
- return { pose: Object.assign({}, last.pose), label: last.label || '' };
99
- }
100
-
101
- for (var i = 0; i < kfs.length - 1; i++) {
102
- var k0 = kfs[i];
103
- var k1 = kfs[i + 1];
104
- if (t >= k0.t && t <= k1.t) {
105
- var dur = k1.t - k0.t;
106
- var p = dur > 0 ? (t - k0.t) / dur : 1.0;
107
- var easeFn = Easings[k1.ease || 'easeInOutQuad'] || Easings.easeInOutQuad;
108
- var ep = easeFn(clamp(p, 0, 1));
109
-
110
- var res = {};
111
- var p0 = k0.pose;
112
- var p1 = k1.pose;
113
- var allKeys = new Set(Object.keys(p0).concat(Object.keys(p1)));
114
- allKeys.forEach(function (key) {
115
- var isScaleKey = key.indexOf('scale') !== -1 || key.indexOf('Scale') !== -1;
116
- var defVal = isScaleKey ? 1.0 : 0.0;
117
- var v0 = p0[key] !== undefined ? p0[key] : (p1[key] !== undefined ? p1[key] : defVal);
118
- var v1 = p1[key] !== undefined ? p1[key] : (p0[key] !== undefined ? p0[key] : defVal);
119
- if (typeof v1 === 'number' && typeof v0 === 'number') {
120
- res[key] = lerp(v0, v1, ep);
121
- } else if (key === 'visible') {
122
- res[key] = Boolean(v0 || v1);
123
- } else {
124
- res[key] = p >= 0.5 ? v1 : v0;
125
- }
126
- });
127
- return { pose: res, label: k1.label || k0.label || '' };
128
- }
129
- }
130
- return { pose: Object.assign({}, kfs[0].pose), label: '' };
131
- };
132
-
133
- function BlinkTrack(blinks) {
134
- this.blinks = blinks || [];
135
- }
136
-
137
- BlinkTrack.prototype.evaluate = function (t) {
138
- for (var i = 0; i < this.blinks.length; i++) {
139
- var b = this.blinks[i];
140
- if (t >= b.start && t <= b.start + b.duration) {
141
- var p = (t - b.start) / b.duration;
142
- return (b.maxSquint || 0.95) * Math.sin(p * Math.PI);
143
- }
144
- }
145
- return 0.0;
146
- };
147
-
148
- function DotGridRig(spacing, baseRadius) {
149
- this.spacing = spacing !== undefined ? spacing : 38.0;
150
- this.baseRadius = baseRadius !== undefined ? baseRadius : 10.1;
151
- }
152
-
153
- DotGridRig.prototype.evaluate = function (t, botScale, botVisible) {
154
- var dots = [];
155
- var phase = t * Math.PI * 2 * 0.9 + 0.66;
156
- var cubeHalf = botVisible ? 68.0 * (botScale || 0.0) : 0.0;
157
-
158
- for (var row = -1; row <= 1; row++) {
159
- for (var col = -1; col <= 1; col++) {
160
- var diag = (col + 1) + (row + 1);
161
- var wave = Math.cos(phase - diag * 0.65);
162
- var r = this.baseRadius + 3.25 * wave;
163
- var x = col * this.spacing;
164
- var y = row * this.spacing;
165
-
166
- var distBox = Math.max(Math.abs(x), Math.abs(y));
167
- var visible = true;
168
-
169
- if (botVisible && botScale > 0.05) {
170
- if (distBox < cubeHalf - 4.0) {
171
- visible = false;
172
- r = 0.0;
173
- } else if (distBox < cubeHalf + 10.0) {
174
- var fade = (distBox - (cubeHalf - 4.0)) / 14.0;
175
- r *= Math.max(0.0, Math.min(1.0, fade));
176
- if (r < 0.5) visible = false;
177
- }
178
- }
179
- dots.push({ x: x, y: y, r: r, visible: visible });
180
- }
181
- }
182
- return dots;
183
- };
184
-
185
- /* =========================================================================
186
- 2. SVG 3D Projector (Minkowski Convex Hull + Face Adherence)
187
- ========================================================================= */
188
- function SvgProjector(options) {
189
- options = options || {};
190
- this.fov = (options.fov || 28.0) * Math.PI / 180.0;
191
- this.focalLength = 1.0 / Math.tan(this.fov / 2.0);
192
- this.camPos = options.cameraPosition || [-0.32, 0.40, 2.70];
193
- this.camTarget = options.cameraTarget || [0.0, 0.0, 0.0];
194
- this.viewportSize = options.viewportSize || 280;
195
-
196
- var c = this.camPos;
197
- var tgt = this.camTarget;
198
- var dist = Math.hypot(tgt[0] - c[0], tgt[1] - c[1], tgt[2] - c[2]);
199
- this.fwd = [(tgt[0] - c[0]) / dist, (tgt[1] - c[1]) / dist, (tgt[2] - c[2]) / dist];
200
-
201
- var up = [0, 1, 0];
202
- var rx = this.fwd[1] * up[2] - this.fwd[2] * up[1];
203
- var ry = this.fwd[2] * up[0] - this.fwd[0] * up[2];
204
- var rz = this.fwd[0] * up[1] - this.fwd[1] * up[0];
205
- var rlen = Math.hypot(rx, ry, rz);
206
- this.right = [rx / rlen, ry / rlen, rz / rlen];
207
-
208
- var ux = this.right[1] * this.fwd[2] - this.right[2] * this.fwd[1];
209
- var uy = this.right[2] * this.fwd[0] - this.right[0] * this.fwd[2];
210
- var uz = this.right[0] * this.fwd[1] - this.right[1] * this.fwd[0];
211
- this.camUp = [ux, uy, uz];
212
-
213
- this.halfSize = this.viewportSize / 2.0;
214
- }
215
-
216
- SvgProjector.prototype.projectWorldPoint = function (wx, wy, wz) {
217
- var dx = wx - this.camPos[0];
218
- var dy = wy - this.camPos[1];
219
- var dz = wz - this.camPos[2];
220
-
221
- var xc = dx * this.right[0] + dy * this.right[1] + dz * this.right[2];
222
- var yc = dx * this.camUp[0] + dy * this.camUp[1] + dz * this.camUp[2];
223
- var zc = dx * this.fwd[0] + dy * this.fwd[1] + dz * this.fwd[2];
224
-
225
- if (zc <= 0.001) return null;
226
- var xs = (xc / zc) * this.focalLength * this.halfSize;
227
- var ys = -(yc / zc) * this.focalLength * this.halfSize;
228
- return { x: xs, y: ys, z: zc };
229
- };
230
-
231
- SvgProjector.getConvexHull = function (pts) {
232
- if (pts.length <= 1) return pts.slice();
233
- var sorted = pts.slice().sort(function (a, b) {
234
- return Math.abs(a.x - b.x) < 1e-5 ? a.y - b.y : a.x - b.x;
235
- });
236
- var cross = function (o, a, b) {
237
- return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
238
- };
239
-
240
- var lower = [];
241
- for (var i = 0; i < sorted.length; i++) {
242
- var p = sorted[i];
243
- while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], p) <= 1e-5) {
244
- lower.pop();
245
- }
246
- lower.push(p);
247
- }
248
-
249
- var upper = [];
250
- for (var j = sorted.length - 1; j >= 0; j--) {
251
- var q = sorted[j];
252
- while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], q) <= 1e-5) {
253
- upper.pop();
254
- }
255
- upper.push(q);
256
- }
257
-
258
- lower.pop();
259
- upper.pop();
260
- var hull = lower.concat(upper);
261
-
262
- var area = 0;
263
- for (var k = 0; k < hull.length; k++) {
264
- var next = (k + 1) % hull.length;
265
- area += hull[k].x * hull[next].y - hull[next].x * hull[k].y;
266
- }
267
- if (area < 0) hull.reverse();
268
- return hull;
269
- };
270
-
271
- SvgProjector.prototype.projectRoundedCube = function (pose, cubeW, cubeRadius) {
272
- cubeW = cubeW !== undefined ? cubeW : 1.0;
273
- cubeRadius = cubeRadius !== undefined ? cubeRadius : 0.35;
274
-
275
- if (!pose || pose.visible === false || (pose.scale !== undefined && pose.scale <= 0.001)) {
276
- return { visible: false, bodyPath: '', eyes: [] };
277
- }
278
-
279
- var s = (pose.scale !== undefined ? pose.scale : 1.0) * 0.60;
280
- var scX = pose.scaleX !== undefined ? pose.scaleX : 1.0;
281
- var scY = pose.scaleY !== undefined ? pose.scaleY : 1.0;
282
- var scZ = pose.scaleZ !== undefined ? pose.scaleZ : 1.0;
283
-
284
- var hw = (cubeW / 2.0) * s * scX;
285
- var hh = (cubeW / 2.0) * s * scY;
286
- var hd = (cubeW / 2.0) * s * scZ;
287
- var r = cubeRadius * s * Math.min(scX, scY);
288
-
289
- var ihw = Math.max(0.001, hw - r);
290
- var ihh = Math.max(0.001, hh - r);
291
- var ihd = Math.max(0.001, hd - r);
292
-
293
- var pitch = pose.pitch || 0.0;
294
- var yaw = pose.yaw || 0.0;
295
- var roll = pose.roll || 0.0;
296
-
297
- var cx = Math.cos(pitch), sx = Math.sin(pitch);
298
- var cy = Math.cos(yaw), sy = Math.sin(yaw);
299
- var cz = Math.cos(roll), sz = Math.sin(roll);
300
-
301
- var r00 = cz * cy;
302
- var r01 = cz * sy * sx - sz * cx;
303
- var r02 = cz * sy * cx + sz * sx;
304
-
305
- var r10 = sz * cy;
306
- var r11 = sz * sy * sx + cz * cx;
307
- var r12 = sz * sy * cx - cz * sx;
308
-
309
- var r20 = -sy;
310
- var r21 = cy * sx;
311
- var r22 = cy * cx;
312
-
313
- var bx = pose.x || 0.0;
314
- var by = pose.y || 0.0;
315
- var bz = pose.z || 0.0;
316
-
317
- var signs = [
318
- [-1, -1, -1], [1, -1, -1], [1, 1, -1], [-1, 1, -1],
319
- [-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1]
320
- ];
321
-
322
- var projPts = [];
323
- var avgZ = 0;
324
-
325
- for (var idx = 0; idx < signs.length; idx++) {
326
- var sgn = signs[idx];
327
- var vx = sgn[0] * ihw;
328
- var vy = sgn[1] * ihh;
329
- var vz = sgn[2] * ihd;
330
-
331
- var wx = bx + (r00 * vx + r01 * vy + r02 * vz);
332
- var wy = by + (r10 * vx + r11 * vy + r12 * vz);
333
- var wz = bz + (r20 * vx + r21 * vy + r22 * vz);
334
-
335
- var p = this.projectWorldPoint(wx, wy, wz);
336
- if (!p) continue;
337
- projPts.push(p);
338
- avgZ += p.z;
339
- }
340
-
341
- if (projPts.length < 4) {
342
- return { visible: false, bodyPath: '', eyes: [] };
343
- }
344
-
345
- avgZ /= projPts.length;
346
- var rScreen = (r / avgZ) * this.focalLength * this.halfSize;
347
-
348
- var hull = SvgProjector.getConvexHull(projPts);
349
- if (hull.length < 3) {
350
- return { visible: false, bodyPath: '', eyes: [] };
351
- }
352
-
353
- var m = hull.length;
354
- var segments = [];
355
- for (var k = 0; k < m; k++) {
356
- var p0 = hull[k];
357
- var p1 = hull[(k + 1) % m];
358
- var dx = p1.x - p0.x;
359
- var dy = p1.y - p0.y;
360
- var len = Math.hypot(dx, dy);
361
- if (len < 1e-5) continue;
362
-
363
- var nx = dy / len;
364
- var ny = -dx / len;
365
-
366
- var a = { x: p0.x + rScreen * nx, y: p0.y + rScreen * ny };
367
- var b = { x: p1.x + rScreen * nx, y: p1.y + rScreen * ny };
368
- segments.push({ a: a, b: b, corner: p1 });
369
- }
370
-
371
- var bodyPath = '';
372
- if (segments.length >= 3) {
373
- var d = [];
374
- for (var si = 0; si < segments.length; si++) {
375
- var seg = segments[si];
376
- var nextSeg = segments[(si + 1) % segments.length];
377
- if (si === 0) {
378
- d.push('M ' + seg.a.x.toFixed(2) + ' ' + seg.a.y.toFixed(2));
379
- }
380
- d.push('L ' + seg.b.x.toFixed(2) + ' ' + seg.b.y.toFixed(2));
381
- d.push('A ' + rScreen.toFixed(2) + ' ' + rScreen.toFixed(2) + ' 0 0 1 ' + nextSeg.a.x.toFixed(2) + ' ' + nextSeg.a.y.toFixed(2));
382
- }
383
- d.push('Z');
384
- bodyPath = d.join(' ');
385
- }
386
-
387
- var eyes = [];
388
- var fnx = r02;
389
- var fny = r12;
390
- var fnz = r22;
391
- var viewDot = -(fnx * this.fwd[0] + fny * this.fwd[1] + fnz * this.fwd[2]);
392
-
393
- var viewFade = 1.0;
394
- if (viewDot <= 0.0) {
395
- viewFade = 0.0;
396
- } else if (viewDot < 0.15) {
397
- var u = viewDot / 0.15;
398
- viewFade = u * u * (3.0 - 2.0 * u);
399
- }
400
-
401
- var showEyes = (pose.showEyes !== false) && (viewFade > 0.001);
402
-
403
- if (showEyes) {
404
- var zFace = (pose.zFace !== undefined ? pose.zFace : 0.508) * s * scZ;
405
- var self = this;
406
-
407
- var computeFeaturePoint = function (fx, fy) {
408
- var wx = bx + (r00 * fx + r01 * fy + r02 * zFace);
409
- var wy = by + (r10 * fx + r11 * fy + r12 * zFace);
410
- var wz = bz + (r20 * fx + r21 * fy + r22 * zFace);
411
- return self.projectWorldPoint(wx, wy, wz);
412
- };
413
-
414
- var getAngle = function (baseP, upP, slant) {
415
- if (!baseP || !upP) return 0;
416
- var adx = upP.x - baseP.x;
417
- var ady = upP.y - baseP.y;
418
- var baseAngle = Math.atan2(adx, -ady) * (180.0 / Math.PI);
419
- return baseAngle - (slant * 180.0 / Math.PI);
420
- };
421
-
422
- var rawFeatures = null;
423
- if (Array.isArray(pose.faceFeatures) && pose.faceFeatures.length > 0) {
424
- rawFeatures = pose.faceFeatures;
425
- } else if (Array.isArray(pose.features) && pose.features.length > 0) {
426
- rawFeatures = pose.features;
427
- } else {
428
- var baseGap = (pose.eyeGap !== undefined ? pose.eyeGap : 0.27) * s * scX;
429
- var eyeX = (pose.eyeShiftX || 0.0) * s * scX;
430
- var baseEyeY = (0.01 - (pose.bulge || 0.0) * 0.02 + (pose.eyeShiftY || 0.0)) * s * scY;
431
- var eyeYL = baseEyeY + (pose.eyeShiftYL || 0.0) * s * scY;
432
- var eyeYR = baseEyeY + (pose.eyeShiftYR || 0.0) * s * scY;
433
-
434
- var slantL = pose.eyeSlantL !== undefined ? pose.eyeSlantL : (pose.eyeSlant || 0.0);
435
- var slantR = pose.eyeSlantR !== undefined ? pose.eyeSlantR : -(pose.eyeSlant || 0.0);
436
-
437
- var sxL = pose.eyeScaleXL !== undefined ? pose.eyeScaleXL : (pose.eyeScaleX !== undefined ? pose.eyeScaleX : 1.0);
438
- var sxR = pose.eyeScaleXR !== undefined ? pose.eyeScaleXR : (pose.eyeScaleX !== undefined ? pose.eyeScaleX : 1.0);
439
- var syL = pose.eyeScaleYL !== undefined ? pose.eyeScaleYL : (pose.eyeScaleY !== undefined ? pose.eyeScaleY : 1.0);
440
- var syR = pose.eyeScaleYR !== undefined ? pose.eyeScaleYR : (pose.eyeScaleY !== undefined ? pose.eyeScaleY : 1.0);
441
-
442
- var eyeSxL = (1.0 + (pose.bulge || 0.0) * 0.45) * sxL;
443
- var eyeSxR = (1.0 + (pose.bulge || 0.0) * 0.45) * sxR;
444
- var eyeSyL = (1.0 + (pose.bulge || 0.0) * 0.65) * syL;
445
- var eyeSyR = (1.0 + (pose.bulge || 0.0) * 0.65) * syR;
446
-
447
- var squint = pose.squint || 0.0;
448
- if (squint > 0.01) {
449
- eyeSyL = eyeSyL * (1.0 - squint) + 0.02 * squint;
450
- eyeSxL = eyeSxL * (1.0 - squint) + 0.85 * squint;
451
- eyeSyR = eyeSyR * (1.0 - squint) + 0.02 * squint;
452
- eyeSxR = eyeSxR * (1.0 - squint) + 0.85 * squint;
453
- }
454
-
455
- rawFeatures = [
456
- {
457
- id: 'eyeL',
458
- type: 'pill',
459
- x: -baseGap / 2 + eyeX,
460
- y: eyeYL,
461
- slant: slantL,
462
- scaleX: eyeSxL,
463
- scaleY: eyeSyL,
464
- baseW: 0.125,
465
- baseH: 0.210,
466
- color: pose.eyeColor || '#ffffff'
467
- },
468
- {
469
- id: 'eyeR',
470
- type: 'pill',
471
- x: baseGap / 2 + eyeX,
472
- y: eyeYR,
473
- slant: slantR,
474
- scaleX: eyeSxR,
475
- scaleY: eyeSyR,
476
- baseW: 0.125,
477
- baseH: 0.210,
478
- color: pose.eyeColor || '#ffffff'
479
- }
480
- ];
481
- }
482
-
483
- var faceForeshorten = Math.max(0.85, Math.hypot(r00, r10));
484
- var squashFade = 0.2 + 0.8 * viewFade;
485
-
486
- for (var fi = 0; fi < rawFeatures.length; fi++) {
487
- var feat = rawFeatures[fi];
488
- var fx = (feat.x !== undefined ? feat.x : 0.0);
489
- var fy = (feat.y !== undefined ? feat.y : 0.0);
490
- var projP = computeFeaturePoint(fx, fy);
491
- if (!projP) continue;
492
-
493
- var projUp = computeFeaturePoint(fx, fy + 0.1 * s * scY);
494
- var fslant = feat.slant || 0.0;
495
- var angle = getAngle(projP, projUp, fslant);
496
-
497
- var factor = projP.z > 0.01 ? (this.focalLength / projP.z) * this.halfSize : (this.focalLength / avgZ) * this.halfSize;
498
- var baseW = feat.baseW !== undefined ? feat.baseW : 0.125;
499
- var baseH = feat.baseH !== undefined ? feat.baseH : 0.210;
500
- var scFeatX = feat.scaleX !== undefined ? feat.scaleX : 1.0;
501
- var scFeatY = feat.scaleY !== undefined ? feat.scaleY : 1.0;
502
-
503
- var ew = Math.max(0.2, baseW * s * scX * scFeatX * faceForeshorten * factor * squashFade);
504
- var eh = Math.max(0.2, baseH * s * scY * scFeatY * factor);
505
- var erx = feat.rx !== undefined ? feat.rx : Math.min(ew, eh) / 2.0;
506
- var ery = feat.ry !== undefined ? feat.ry : Math.min(ew, eh) / 2.0;
507
-
508
- var featOpacity = (feat.opacity !== undefined ? feat.opacity : 1.0) * viewFade;
509
-
510
- eyes.push({
511
- id: feat.id || ('feat-' + fi),
512
- type: feat.type || 'pill',
513
- cx: projP.x,
514
- cy: projP.y,
515
- z: projP.z,
516
- w: ew,
517
- h: eh,
518
- rx: erx,
519
- ry: ery,
520
- angle: angle,
521
- opacity: featOpacity,
522
- color: feat.color || pose.eyeColor || '#ffffff'
523
- });
524
- }
525
- }
526
-
527
- return {
528
- visible: true,
529
- bodyPath: bodyPath,
530
- eyes: eyes,
531
- bodyColor: pose.bodyColor,
532
- eyeColor: pose.eyeColor
533
- };
534
- };
535
-
536
- /* =========================================================================
537
- 3. Mascot Timelines & State Functions (#1 ~ #7)
538
- ========================================================================= */
539
-
540
- // --- #1 Sentry (哨兵) ---
541
- var pBot1Start = { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: -0.02, roll: 0.01, eyeShiftX: 0.015, eyeShiftY: -0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeScaleXL: 1.0, eyeScaleXR: 1.0, eyeGap: 0.26, bulge: 0.0, jumpY: 0.0 };
542
- var pBot1Left = { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.28, pitch: -0.03, roll: 0.02, eyeShiftX: -0.080, eyeShiftY: 0.01, eyeScaleX: 0.95, eyeScaleY: 1.0, eyeScaleXL: 0.94, eyeScaleXR: 1.0, eyeGap: 0.22, bulge: 0.0, jumpY: 0.0 };
543
- var pBot1DeepLeft = { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.42, pitch: -0.05, roll: 0.04, eyeShiftX: -0.108, eyeShiftY: 0.03, eyeScaleX: 0.95, eyeScaleY: 1.0, eyeScaleXL: 0.92, eyeScaleXR: 1.0, eyeGap: 0.20, bulge: 0.0, jumpY: 0.0 };
544
- var pBot1Right = { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.36, pitch: -0.04, roll: -0.03, eyeShiftX: 0.075, eyeShiftY: 0.02, eyeScaleX: 0.95, eyeScaleY: 1.0, eyeScaleXL: 1.0, eyeScaleXR: 0.94, eyeGap: 0.22, bulge: 0.0, jumpY: 0.0 };
545
- var pBot1FarRight = { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.44, pitch: -0.05, roll: -0.04, eyeShiftX: 0.095, eyeShiftY: 0.025, eyeScaleX: 0.95, eyeScaleY: 1.0, eyeScaleXL: 1.0, eyeScaleXR: 0.92, eyeGap: 0.20, bulge: 0.0, jumpY: 0.0 };
546
- var pBot1MidFocus = { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.00, pitch: -0.02, roll: 0.0, eyeShiftX: 0.00, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeScaleXL: 1.0, eyeScaleXR: 1.0, eyeGap: 0.26, bulge: 0.0, jumpY: 0.0 };
547
- var pBot1Stretch = { scale: 1.0, scaleX: 0.97, scaleY: 1.04, yaw: 0.38, pitch: -0.06, roll: 0.0, eyeShiftX: 0.075, eyeShiftY: 0.04, eyeScaleX: 0.95, eyeScaleY: 1.0, eyeScaleXL: 1.0, eyeScaleXR: 0.94, eyeGap: 0.22, bulge: 0.0, jumpY: 0.012 };
548
- var pBot1Tilt = { scale: 1.0, scaleX: 0.97, scaleY: 1.04, yaw: 0.40, pitch: -0.06, roll: 0.320, eyeShiftX: 0.085, eyeShiftY: 0.035, eyeScaleX: 0.95, eyeScaleY: 1.0, eyeScaleXL: 1.0, eyeScaleXR: 0.94, eyeGap: 0.21, bulge: 0.0, jumpY: 0.012 };
549
-
550
- var bot1Timeline = new PoseTimeline([
551
- { t: 0.00, label: 'sentry-scan-left-1', pose: pBot1Start },
552
- { t: 1.65, label: 'sentry-scan-left-1', ease: 'linear', pose: pBot1Start },
553
- { t: 2.15, label: 'sentry-sweep-right-1', ease: 'easeInOutQuad', pose: pBot1Right },
554
- { t: 3.60, label: 'sentry-sweep-right-1', ease: 'linear', pose: pBot1Right },
555
- { t: 3.88, label: 'sentry-scan-left-2', ease: 'easeInOutQuad', pose: pBot1Left },
556
- { t: 4.65, label: 'sentry-scan-left-2', ease: 'linear', pose: pBot1Left },
557
- { t: 5.30, label: 'sentry-sweep-right-2', ease: 'easeInOutQuad', pose: pBot1Right },
558
- { t: 6.60, label: 'sentry-sweep-right-2', ease: 'linear', pose: pBot1Right },
559
- { t: 7.10, label: 'sentry-sweep-far-right', ease: 'easeInOutQuad', pose: pBot1FarRight },
560
- { t: 8.40, label: 'sentry-sweep-far-right', ease: 'linear', pose: pBot1FarRight },
561
- { t: 8.75, label: 'sentry-deep-left-1', ease: 'easeInOutQuad', pose: pBot1DeepLeft },
562
- { t: 9.35, label: 'sentry-deep-left-1', ease: 'linear', pose: pBot1DeepLeft },
563
- { t: 9.90, label: 'sentry-sweep-right-3', ease: 'easeInOutQuad', pose: pBot1Right },
564
- { t: 11.20, label: 'sentry-sweep-right-3', ease: 'linear', pose: pBot1Right },
565
- { t: 11.55, label: 'sentry-center-focus', ease: 'easeInOutQuad', pose: pBot1MidFocus },
566
- { t: 14.10, label: 'sentry-center-focus', ease: 'linear', pose: pBot1MidFocus },
567
- { t: 14.45, label: 'sentry-deep-left-2', ease: 'easeInOutQuad', pose: pBot1DeepLeft },
568
- { t: 15.15, label: 'sentry-deep-left-2', ease: 'linear', pose: pBot1DeepLeft },
569
- { t: 15.65, label: 'sentry-sweep-right-4', ease: 'easeInOutQuad', pose: pBot1Right },
570
- { t: 16.80, label: 'sentry-sweep-right-4', ease: 'linear', pose: pBot1Right },
571
- { t: 17.05, label: 'sentry-stretch', ease: 'easeInOutQuad', pose: pBot1Stretch },
572
- { t: 17.35, label: 'sentry-curious-tilt', ease: 'easeInOutQuad', pose: pBot1Tilt },
573
- { t: 18.70, label: 'sentry-curious-tilt', ease: 'linear', pose: pBot1Tilt },
574
- { t: 19.05, label: 'sentry-right-settle', ease: 'easeInOutQuad', pose: pBot1Right },
575
- { t: 19.45, label: 'sentry-scan-left-3', ease: 'easeInOutQuad', pose: pBot1Left },
576
- { t: 20.20, label: 'sentry-deep-left-3', ease: 'easeInOutQuad', pose: pBot1DeepLeft },
577
- { t: 20.783, label: 'sentry-scan-left-1', ease: 'easeInOutQuad', pose: pBot1Start }
578
- ]);
579
-
580
- var bot1Blinks = new BlinkTrack([
581
- { start: 1.85, duration: 0.18, maxSquint: 0.98 },
582
- { start: 5.65, duration: 0.17, maxSquint: 0.98 },
583
- { start: 8.80, duration: 0.18, maxSquint: 0.98 },
584
- { start: 11.40, duration: 0.18, maxSquint: 0.98 },
585
- { start: 11.68, duration: 0.19, maxSquint: 0.98 },
586
- { start: 16.10, duration: 0.18, maxSquint: 0.98 },
587
- { start: 18.96, duration: 0.18, maxSquint: 0.98 }
588
- ]);
589
-
590
- function getBot1State(time) {
591
- var t = ((time % LOOP) + LOOP) % LOOP;
592
- var res = bot1Timeline.evaluate(t);
593
- var pose = res.pose;
594
- var squint = bot1Blinks.evaluate(t);
595
-
596
- var bot = {
597
- visible: true,
598
- scale: pose.scale,
599
- scaleX: pose.scaleX,
600
- scaleY: pose.scaleY,
601
- x: 0.0,
602
- y: pose.jumpY || 0.0,
603
- yaw: pose.yaw,
604
- pitch: pose.pitch,
605
- roll: pose.roll,
606
- eyeShiftX: pose.eyeShiftX,
607
- eyeShiftY: pose.eyeShiftY,
608
- eyeScaleX: pose.eyeScaleX,
609
- eyeScaleY: pose.eyeScaleY,
610
- eyeScaleXL: pose.eyeScaleXL !== undefined ? pose.eyeScaleXL : 1.0,
611
- eyeScaleXR: pose.eyeScaleXR !== undefined ? pose.eyeScaleXR : 1.0,
612
- eyeGap: pose.eyeGap !== undefined ? pose.eyeGap : 0.23,
613
- bulge: pose.bulge || 0.0,
614
- squint: squint,
615
- bodyColor: 0x222126,
616
- eyeColor: 0xffffff
617
- };
618
-
619
- return { botId: 1, type: 'bot1', label: res.label, bot: bot, dots: [] };
620
- }
621
-
622
- // --- #2 Attitude (傲娇小怪) ---
623
- var bot2Apexes = [1.07, 4.78, 8.57, 12.20, 15.90, 19.62];
624
- var BOT2_FLIP_HALF = 0.42;
625
-
626
- function makeBot2RelaxedPose(cycle) {
627
- return {
628
- scale: 1.0, scaleX: 1.0, scaleY: 1.0,
629
- yaw: 0.05, pitch: 0.02,
630
- roll: 0.17 + cycle * 2 * Math.PI,
631
- eyeShiftX: 0.04, eyeShiftY: 0.22,
632
- eyeShiftYL: 0.0, eyeShiftYR: 0.0,
633
- eyeScaleXL: 1.0, eyeScaleYL: 1.0,
634
- eyeScaleXR: 1.0, eyeScaleYR: 1.0,
635
- eyeSlantL: 0.0, eyeSlantR: 0.10,
636
- eyeGap: 0.22, bulge: 0.0, jumpY: 0.0, showEyes: true
637
- };
638
- }
639
-
640
- function makeBot2MidPose(cycle) {
641
- return {
642
- scale: 1.0, scaleX: 1.0, scaleY: 1.0,
643
- yaw: 0.85, pitch: 0.35,
644
- roll: 0.17 + (cycle * 2 + 1) * Math.PI,
645
- eyeShiftX: 0.04, eyeShiftY: 0.22,
646
- eyeShiftYL: 0.0, eyeShiftYR: 0.0,
647
- eyeScaleXL: 0.85, eyeScaleYL: 0.85,
648
- eyeScaleXR: 0.85, eyeScaleYR: 0.85,
649
- eyeSlantL: 0.0, eyeSlantR: 0.0,
650
- eyeGap: 0.22, bulge: 0.0, jumpY: 0.075, showEyes: false
651
- };
652
- }
653
-
654
- function makeBot2SquintPose(cycle) {
655
- return {
656
- scale: 1.0, scaleX: 1.0, scaleY: 1.0,
657
- yaw: 0.05, pitch: 0.02,
658
- roll: 0.17 + cycle * 2 * Math.PI,
659
- eyeShiftX: 0.04, eyeShiftY: 0.22,
660
- eyeShiftYL: -0.015, eyeShiftYR: +0.020,
661
- eyeScaleXL: 0.60, eyeScaleXR: 0.60,
662
- eyeScaleYL: 0.85, eyeScaleYR: 0.85,
663
- eyeSlantL: 0.56, eyeSlantR: -0.51,
664
- eyeGap: 0.22, bulge: 0.0, jumpY: 0.0, showEyes: true
665
- };
666
- }
667
-
668
- var bot2Keyframes = [
669
- { t: 0.00, label: 'standby-relaxed-0', pose: makeBot2RelaxedPose(0) }
670
- ];
671
-
672
- for (var bi = 0; bi < bot2Apexes.length; bi++) {
673
- var apex = bot2Apexes[bi];
674
- var tTakeoff = apex - BOT2_FLIP_HALF;
675
- var tMid = apex;
676
- var tLand = apex + BOT2_FLIP_HALF;
677
- var tSquintSnap = tLand + 0.08;
678
-
679
- bot2Keyframes.push({ t: tTakeoff, label: 'takeoff-' + bi, ease: 'linear', pose: makeBot2RelaxedPose(bi) });
680
- bot2Keyframes.push({ t: tMid, label: 'spin-flip-mid-' + (bi + 1), ease: 'easeInOutQuad', pose: makeBot2MidPose(bi) });
681
- bot2Keyframes.push({ t: tLand, label: 'spin-flip-land-' + (bi + 1), ease: 'easeInOutQuad', pose: makeBot2SquintPose(bi + 1) });
682
- bot2Keyframes.push({ t: tSquintSnap, label: 'attitude-squint-' + (bi + 1), ease: 'linear', pose: makeBot2SquintPose(bi + 1) });
683
-
684
- if (bi < bot2Apexes.length - 1) {
685
- var nextApex = bot2Apexes[bi + 1];
686
- var nextTakeoff = nextApex - BOT2_FLIP_HALF;
687
- var tSquintHoldEnd = nextTakeoff - 0.65;
688
- var tRelaxEnd = nextTakeoff - 0.35;
689
-
690
- bot2Keyframes.push({ t: tSquintHoldEnd, label: 'attitude-hold-' + (bi + 1), ease: 'linear', pose: makeBot2SquintPose(bi + 1) });
691
- bot2Keyframes.push({ t: tRelaxEnd, label: 'attitude-relax-' + (bi + 1), ease: 'easeInOutQuad', pose: makeBot2RelaxedPose(bi + 1) });
692
- } else {
693
- bot2Keyframes.push({ t: 20.45, label: 'attitude-hold-6', ease: 'linear', pose: makeBot2SquintPose(6) });
694
- bot2Keyframes.push({ t: 20.783, label: 'attitude-relax-end', ease: 'easeInOutQuad', pose: makeBot2RelaxedPose(6) });
695
- }
696
- }
697
-
698
- var bot2Timeline = new PoseTimeline(bot2Keyframes);
699
- var bot2Blinks = new BlinkTrack([]);
700
-
701
- function getBot2State(time) {
702
- var t = ((time % LOOP) + LOOP) % LOOP;
703
- var res = bot2Timeline.evaluate(t);
704
- var pose = res.pose;
705
- var squint = bot2Blinks.evaluate(t);
706
-
707
- var squintWeight = Math.max(0.0, Math.min(1.0, (pose.eyeSlantL || 0.0) / 0.56));
708
- var omegaShake = 2.2 * Math.PI * 2.0;
709
- var headShakeYaw = Math.sin(t * omegaShake) * 0.038 * squintWeight;
710
- var headShakeRoll = Math.cos(t * omegaShake) * 0.024 * squintWeight;
711
- var headShakeEyeX = Math.sin(t * omegaShake) * 0.010 * squintWeight;
712
- var headShakeEyeY = Math.abs(Math.sin(t * omegaShake)) * 0.005 * squintWeight;
713
-
714
- var bot = {
715
- visible: true,
716
- scale: pose.scale,
717
- scaleX: pose.scaleX,
718
- scaleY: pose.scaleY,
719
- x: 0.0,
720
- y: pose.jumpY || 0.0,
721
- yaw: (pose.yaw || 0.0) + headShakeYaw,
722
- pitch: pose.pitch,
723
- roll: (pose.roll || 0.0) + headShakeRoll,
724
- eyeShiftX: (pose.eyeShiftX || 0.0) + headShakeEyeX,
725
- eyeShiftY: (pose.eyeShiftY || 0.0) + headShakeEyeY,
726
- eyeShiftYL: pose.eyeShiftYL,
727
- eyeShiftYR: pose.eyeShiftYR,
728
- eyeScaleX: pose.eyeScaleX,
729
- eyeScaleY: pose.eyeScaleY,
730
- eyeScaleXL: pose.eyeScaleXL,
731
- eyeScaleXR: pose.eyeScaleXR,
732
- eyeScaleYL: pose.eyeScaleYL,
733
- eyeScaleYR: pose.eyeScaleYR,
734
- eyeSlantL: pose.eyeSlantL,
735
- eyeSlantR: pose.eyeSlantR,
736
- eyeGap: pose.eyeGap !== undefined ? pose.eyeGap : 0.22,
737
- bulge: pose.bulge || 0.0,
738
- squint: squint,
739
- showEyes: pose.showEyes,
740
- bodyColor: 0x222126,
741
- eyeColor: 0xffffff
742
- };
743
-
744
- return { botId: 2, type: 'bot2', label: res.label, bot: bot, dots: [] };
745
- }
746
-
747
- // --- #3 Chameleon (动感变色龙) ---
748
- var BOT3_PALETTE_12 = [
749
- [ 58, 53, 206], // 0.0s 钴蓝
750
- [ 60, 84, 208], // 0.5s 浅钴蓝
751
- [201, 34, 153], // 1.0s 洋红
752
- [201, 222, 65], // 1.5s 柠黄
753
- [ 68, 229, 198], // 2.0s 青绿
754
- [ 66, 162, 209], // 2.5s 天蓝
755
- [ 69, 238, 80], // 3.0s 亮绿
756
- [200, 41, 71], // 3.5s 绯红
757
- [125, 38, 208], // 4.0s 紫色
758
- [100, 42, 209], // 4.5s 蓝紫
759
- [154, 36, 211], // 5.0s 亮紫
760
- [199, 35, 104] // 5.5s 玫红
761
- ];
762
-
763
- function getBot3ColorHex(t) {
764
- var cycle = ((t % 6.00) + 6.00) % 6.00 / 6.00;
765
- var n = BOT3_PALETTE_12.length;
766
- var p = cycle * n;
767
- var i0 = Math.floor(p) % n;
768
- var i1 = (i0 + 1) % n;
769
- var f = p - Math.floor(p);
770
- var s = f * f * (3 - 2 * f);
771
- var r = Math.round(BOT3_PALETTE_12[i0][0] * (1 - s) + BOT3_PALETTE_12[i1][0] * s);
772
- var g = Math.round(BOT3_PALETTE_12[i0][1] * (1 - s) + BOT3_PALETTE_12[i1][1] * s);
773
- var b = Math.round(BOT3_PALETTE_12[i0][2] * (1 - s) + BOT3_PALETTE_12[i1][2] * s);
774
- return (r << 16) | (g << 8) | b;
775
- }
776
-
777
- var bot3Timeline = new PoseTimeline([
778
- { t: 0.00, label: 'chameleon-normal', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
779
- { t: 1.20, label: 'chameleon-normal', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
780
- { t: 1.50, label: 'chameleon-slit-1', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.52, eyeScaleY: 0.82, eyeScaleXL: 0.52, eyeScaleXR: 0.52, eyeScaleYL: 0.82, eyeScaleYR: 0.82, eyeSlantL: 0.58, eyeSlantR: -0.58, bulge: 0.0, jumpY: 0.0 } },
781
- { t: 1.70, label: 'chameleon-slit-1', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.52, eyeScaleY: 0.82, eyeScaleXL: 0.52, eyeScaleXR: 0.52, eyeScaleYL: 0.82, eyeScaleYR: 0.82, eyeSlantL: 0.58, eyeSlantR: -0.58, bulge: 0.0, jumpY: 0.0 } },
782
- { t: 1.95, label: 'chameleon-dot-1', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.40, eyeScaleY: 0.40, eyeScaleXL: 0.40, eyeScaleXR: 0.40, eyeScaleYL: 0.40, eyeScaleYR: 0.40, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
783
- { t: 2.15, label: 'chameleon-dot-1', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.40, eyeScaleY: 0.40, eyeScaleXL: 0.40, eyeScaleXR: 0.40, eyeScaleYL: 0.40, eyeScaleYR: 0.40, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
784
- { t: 2.45, label: 'chameleon-normal', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
785
- { t: 2.75, label: 'chameleon-slit-2', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.52, eyeScaleY: 0.82, eyeScaleXL: 0.52, eyeScaleXR: 0.52, eyeScaleYL: 0.82, eyeScaleYR: 0.82, eyeSlantL: 0.58, eyeSlantR: -0.58, bulge: 0.0, jumpY: 0.0 } },
786
- { t: 3.15, label: 'chameleon-slit-2', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.52, eyeScaleY: 0.82, eyeScaleXL: 0.52, eyeScaleXR: 0.52, eyeScaleYL: 0.82, eyeScaleYR: 0.82, eyeSlantL: 0.58, eyeSlantR: -0.58, bulge: 0.0, jumpY: 0.0 } },
787
- { t: 3.50, label: 'chameleon-normal', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
788
- { t: 4.80, label: 'chameleon-slit-3', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.52, eyeScaleY: 0.82, eyeScaleXL: 0.52, eyeScaleXR: 0.52, eyeScaleYL: 0.82, eyeScaleYR: 0.82, eyeSlantL: 0.58, eyeSlantR: -0.58, bulge: 0.0, jumpY: 0.0 } },
789
- { t: 5.30, label: 'chameleon-slit-3', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.52, eyeScaleY: 0.82, eyeScaleXL: 0.52, eyeScaleXR: 0.52, eyeScaleYL: 0.82, eyeScaleYR: 0.82, eyeSlantL: 0.58, eyeSlantR: -0.58, bulge: 0.0, jumpY: 0.0 } },
790
- { t: 5.70, label: 'chameleon-normal', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
791
- { t: 8.60, label: 'chameleon-normal', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
792
- { t: 8.90, label: 'chameleon-corner-glance-1', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.15, pitch: -0.04, roll: -0.10, eyeShiftX: -0.16, eyeShiftY: 0.11, eyeGap: 0.36, eyeScaleX: 0.52, eyeScaleY: 0.52, eyeScaleXL: 0.50, eyeScaleXR: 0.55, eyeScaleYL: 0.50, eyeScaleYR: 0.55, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
793
- { t: 9.20, label: 'chameleon-corner-glance-1', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.15, pitch: -0.04, roll: -0.10, eyeShiftX: -0.16, eyeShiftY: 0.11, eyeGap: 0.36, eyeScaleX: 0.52, eyeScaleY: 0.52, eyeScaleXL: 0.50, eyeScaleXR: 0.55, eyeScaleYL: 0.50, eyeScaleYR: 0.55, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
794
- { t: 9.50, label: 'chameleon-normal', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
795
- { t: 11.20, label: 'chameleon-normal', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
796
- { t: 11.50, label: 'chameleon-asym', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.50, eyeScaleY: 0.62, eyeScaleXL: 0.40, eyeScaleXR: 0.60, eyeScaleYL: 0.40, eyeScaleYR: 0.85, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
797
- { t: 11.80, label: 'chameleon-normal', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
798
- { t: 14.60, label: 'chameleon-normal', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
799
- { t: 14.85, label: 'chameleon-corner-glance-2', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.15, pitch: -0.04, roll: -0.10, eyeShiftX: -0.16, eyeShiftY: 0.11, eyeGap: 0.36, eyeScaleX: 0.52, eyeScaleY: 0.52, eyeScaleXL: 0.50, eyeScaleXR: 0.55, eyeScaleYL: 0.50, eyeScaleYR: 0.55, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
800
- { t: 15.05, label: 'chameleon-corner-glance-2', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.15, pitch: -0.04, roll: -0.10, eyeShiftX: -0.16, eyeShiftY: 0.11, eyeGap: 0.36, eyeScaleX: 0.52, eyeScaleY: 0.52, eyeScaleXL: 0.50, eyeScaleXR: 0.55, eyeScaleYL: 0.50, eyeScaleYR: 0.55, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
801
- { t: 15.18, label: 'chameleon-dazed', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.02, pitch: 0.01, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.75, eyeScaleY: 0.45, eyeScaleXL: 0.75, eyeScaleXR: 0.75, eyeScaleYL: 0.45, eyeScaleYR: 0.45, eyeSlantL: 0.10, eyeSlantR: -0.10, bulge: 0.0, jumpY: 0.0 } },
802
- { t: 16.14, label: 'chameleon-dazed', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.02, pitch: 0.01, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.75, eyeScaleY: 0.45, eyeScaleXL: 0.75, eyeScaleXR: 0.75, eyeScaleYL: 0.45, eyeScaleYR: 0.45, eyeSlantL: 0.10, eyeSlantR: -0.10, bulge: 0.0, jumpY: 0.0 } },
803
- { t: 16.40, label: 'chameleon-normal', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
804
- { t: 17.00, label: 'chameleon-slit-4', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.52, eyeScaleY: 0.82, eyeScaleXL: 0.52, eyeScaleXR: 0.52, eyeScaleYL: 0.82, eyeScaleYR: 0.82, eyeSlantL: 0.58, eyeSlantR: -0.58, bulge: 0.0, jumpY: 0.0 } },
805
- { t: 17.60, label: 'chameleon-slit-4', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.52, eyeScaleY: 0.82, eyeScaleXL: 0.52, eyeScaleXR: 0.52, eyeScaleYL: 0.82, eyeScaleYR: 0.82, eyeSlantL: 0.58, eyeSlantR: -0.58, bulge: 0.0, jumpY: 0.0 } },
806
- { t: 18.00, label: 'chameleon-normal', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
807
- { t: 19.80, label: 'chameleon-normal', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
808
- { t: 20.00, label: 'chameleon-corner-glance-3', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.15, pitch: -0.04, roll: -0.10, eyeShiftX: -0.16, eyeShiftY: 0.11, eyeGap: 0.36, eyeScaleX: 0.52, eyeScaleY: 0.52, eyeScaleXL: 0.50, eyeScaleXR: 0.55, eyeScaleYL: 0.50, eyeScaleYR: 0.55, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
809
- { t: 20.25, label: 'chameleon-corner-glance-3', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.15, pitch: -0.04, roll: -0.10, eyeShiftX: -0.16, eyeShiftY: 0.11, eyeGap: 0.36, eyeScaleX: 0.52, eyeScaleY: 0.52, eyeScaleXL: 0.50, eyeScaleXR: 0.55, eyeScaleYL: 0.50, eyeScaleYR: 0.55, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
810
- { t: 20.50, label: 'chameleon-normal', ease: 'easeInOutQuad', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } },
811
- { t: 20.783, label: 'chameleon-normal', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.05, pitch: 0.02, roll: -0.10, eyeShiftX: 0.02, eyeShiftY: 0.09, eyeGap: 0.27, eyeScaleX: 0.90, eyeScaleY: 1.05, eyeScaleXL: 0.90, eyeScaleXR: 0.90, eyeScaleYL: 1.05, eyeScaleYR: 1.05, eyeSlantL: 0.0, eyeSlantR: 0.0, bulge: 0.0, jumpY: 0.0 } }
812
- ]);
813
-
814
- var bot3Blinks = new BlinkTrack([
815
- { start: 1.85, duration: 0.18, maxSquint: 0.95 },
816
- { start: 5.65, duration: 0.17, maxSquint: 0.95 },
817
- { start: 8.80, duration: 0.18, maxSquint: 0.95 },
818
- { start: 11.40, duration: 0.18, maxSquint: 0.95 },
819
- { start: 11.70, duration: 0.18, maxSquint: 0.95 },
820
- { start: 16.12, duration: 0.18, maxSquint: 0.95 },
821
- { start: 18.96, duration: 0.18, maxSquint: 0.95 }
822
- ]);
823
-
824
- function getBot3State(time) {
825
- var t = ((time % LOOP) + LOOP) % LOOP;
826
- var colorHex = getBot3ColorHex(t);
827
- var res = bot3Timeline.evaluate(t);
828
- var pose = res.pose;
829
- var squint = bot3Blinks.evaluate(t);
830
-
831
- var N_DANCE_CYCLES = 21;
832
- var omegaSway = (2.0 * Math.PI * N_DANCE_CYCLES) / LOOP;
833
- var omegaBounce = 4.0 * omegaSway;
834
-
835
- var bouncePhase = (t * omegaBounce) % (2.0 * Math.PI);
836
- var bounceShape = Math.pow(Math.sin(bouncePhase / 2.0), 2.0);
837
- var bounceY = (bounceShape - 0.48) * 0.052;
838
-
839
- var squashNorm = (bounceShape - 0.48) * 2.0;
840
- var danceScaleX = (pose.scaleX || 1.0) * (1.0 + squashNorm * 0.068);
841
- var danceScaleY = (pose.scaleY || 1.0) * (1.0 - squashNorm * 0.068);
842
-
843
- var swayX = Math.sin(t * omegaSway) * 0.15;
844
- var swayRoll = -Math.sin(t * omegaSway) * 0.20 + Math.cos(t * omegaBounce) * 0.035;
845
-
846
- var bot = {
847
- visible: true,
848
- scale: pose.scale || 1.0,
849
- scaleX: danceScaleX,
850
- scaleY: danceScaleY,
851
- x: (pose.x || 0.0) + swayX,
852
- y: (pose.jumpY || 0.0) + bounceY,
853
- jumpY: (pose.jumpY || 0.0) + bounceY,
854
- yaw: pose.yaw || 0.0,
855
- pitch: pose.pitch || 0.0,
856
- roll: (pose.roll || 0.0) + swayRoll,
857
- eyeShiftX: pose.eyeShiftX !== undefined ? pose.eyeShiftX : 0.02,
858
- eyeShiftY: pose.eyeShiftY !== undefined ? pose.eyeShiftY : (0.09 - bounceY * 0.25),
859
- eyeScaleX: pose.eyeScaleX,
860
- eyeScaleY: pose.eyeScaleY,
861
- eyeScaleXL: pose.eyeScaleXL !== undefined ? pose.eyeScaleXL : (pose.eyeScaleX !== undefined ? pose.eyeScaleX : 0.90),
862
- eyeScaleXR: pose.eyeScaleXR !== undefined ? pose.eyeScaleXR : (pose.eyeScaleX !== undefined ? pose.eyeScaleX : 0.90),
863
- eyeScaleYL: pose.eyeScaleYL !== undefined ? pose.eyeScaleYL : (pose.eyeScaleY !== undefined ? pose.eyeScaleY : 1.05),
864
- eyeScaleYR: pose.eyeScaleYR !== undefined ? pose.eyeScaleYR : (pose.eyeScaleY !== undefined ? pose.eyeScaleY : 1.05),
865
- eyeSlantL: pose.eyeSlantL !== undefined ? pose.eyeSlantL : (pose.eyeSlant || 0.0),
866
- eyeSlantR: pose.eyeSlantR !== undefined ? pose.eyeSlantR : -(pose.eyeSlant || 0.0),
867
- eyeGap: pose.eyeGap !== undefined ? pose.eyeGap : 0.27,
868
- bulge: pose.bulge || 0.0,
869
- squint: squint,
870
- bodyColor: colorHex,
871
- eyeColor: 0x222126
872
- };
873
-
874
- return { botId: 3, type: 'bot3', label: res.label, bot: bot, dots: [] };
875
- }
876
-
877
- // --- #4 Observer (屏读观察者) ---
878
- var BOT4_T_ROW = LOOP / 16.0;
879
- var pBot4Pose = function (yaw, eyeShiftX) {
880
- return {
881
- scale: 1.0, scaleX: 1.0, scaleY: 1.0,
882
- yaw: yaw, pitch: 0.0, roll: 0.0,
883
- eyeShiftX: eyeShiftX, eyeShiftY: 0.0,
884
- bulge: 0.0, jumpY: 0.0
885
- };
886
- };
887
-
888
- var bot4Keyframes = [
889
- { t: 0.00, label: 'raster-0-right', pose: pBot4Pose(0.26, 0.042) }
890
- ];
891
-
892
- for (var k = 0; k < 16; k++) {
893
- var tBase = k * BOT4_T_ROW;
894
- var tSnapStart = tBase + 0.12;
895
- var tLeftLand = tBase + 0.24;
896
- var tLeftEnd = tBase + 0.52;
897
- var tCenterLand = tBase + 0.60;
898
- var tCenterEnd = tBase + 0.88;
899
- var tRightLand = tBase + 0.96;
900
-
901
- bot4Keyframes.push({ t: tSnapStart, label: 'raster-' + k + '-hold-right', ease: 'linear', pose: pBot4Pose(0.26, 0.042) });
902
- bot4Keyframes.push({ t: tLeftLand, label: 'raster-' + k + '-snap-left', ease: 'easeInOutQuad', pose: pBot4Pose(-0.26, -0.042) });
903
- bot4Keyframes.push({ t: tLeftEnd, label: 'raster-' + k + '-hold-left', ease: 'linear', pose: pBot4Pose(-0.26, -0.042) });
904
- bot4Keyframes.push({ t: tCenterLand, label: 'raster-' + k + '-step-center', ease: 'easeInOutQuad', pose: pBot4Pose(0.00, 0.000) });
905
- bot4Keyframes.push({ t: tCenterEnd, label: 'raster-' + k + '-hold-center', ease: 'linear', pose: pBot4Pose(0.00, 0.000) });
906
- bot4Keyframes.push({ t: tRightLand, label: 'raster-' + k + '-step-right', ease: 'easeInOutQuad', pose: pBot4Pose(0.26, 0.042) });
907
-
908
- if (k < 15) {
909
- bot4Keyframes.push({ t: (k + 1) * BOT4_T_ROW, label: 'raster-' + (k + 1) + '-init', ease: 'linear', pose: pBot4Pose(0.26, 0.042) });
910
- }
911
- }
912
- bot4Keyframes.push({ t: LOOP, label: 'raster-end', ease: 'linear', pose: pBot4Pose(0.26, 0.042) });
913
-
914
- var bot4Timeline = new PoseTimeline(bot4Keyframes);
915
-
916
- function getBot4State(time) {
917
- var t = ((time % LOOP) + LOOP) % LOOP;
918
- var res = bot4Timeline.evaluate(t);
919
- var pose = res.pose;
920
-
921
- var bot = {
922
- visible: true,
923
- scale: pose.scale,
924
- scaleX: pose.scaleX,
925
- scaleY: pose.scaleY,
926
- x: 0.0,
927
- y: 0.0,
928
- yaw: pose.yaw,
929
- pitch: pose.pitch,
930
- roll: pose.roll,
931
- eyeShiftX: pose.eyeShiftX,
932
- eyeShiftY: pose.eyeShiftY,
933
- eyeScaleX: 0.96,
934
- eyeScaleY: 0.96,
935
- eyeGap: 0.22,
936
- bulge: 0.0,
937
- squint: 0.0,
938
- bodyColor: 0x222126,
939
- eyeColor: 0xffffff
940
- };
941
-
942
- return { botId: 4, type: 'bot4', label: res.label, bot: bot, dots: [] };
943
- }
944
-
945
- // --- #5 Cube & Grid (方块与点阵) ---
946
- var bot5Timeline = new PoseTimeline([
947
- { t: 0.00, label: 'tucked', pose: { scaleX: 1.0, scaleY: 1.0, visible: false, scale: 0.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
948
- { t: 2.22, label: 'tucked', pose: { scaleX: 1.0, scaleY: 1.0, visible: false, scale: 0.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
949
- { t: 2.45, label: 'bouncy-pop-spin', ease: 'easeInOutQuad', pose: { scaleX: 1.0, scaleY: 1.0, visible: true, scale: 1.08, yaw: -Math.PI * 0.55, pitch: -0.02, roll: 0.04, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.06 } },
950
- { t: 2.68, label: 'bouncy-pop-spin', ease: 'easeInOutQuad', pose: { scaleX: 1.0, scaleY: 1.0, visible: true, scale: 1.03, yaw: -Math.PI * 1.03, pitch: -0.04, roll: 0.02, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.02 } },
951
- { t: 2.92, label: 'spin-reappear', ease: 'easeInOutQuad', pose: { scaleX: 1.0, scaleY: 1.0, visible: true, scale: 1.00, yaw: -Math.PI * 1.58, pitch: -0.05, roll: -0.03, eyeShiftX: -0.05, eyeShiftY: 0.035, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
952
- { t: 3.06, label: 'land-settle', ease: 'easeOutCubic', pose: { scaleX: 1.0, scaleY: 1.0, visible: true, scale: 1.00, yaw: -Math.PI * 2.0 + 0.31, pitch: -0.05, roll: -0.05, eyeShiftX: -0.05, eyeShiftY: 0.035, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
953
- { t: 3.28, label: 'eye-bulge', ease: 'easeInOutQuad', pose: { scaleX: 1.0, scaleY: 1.0, visible: true, scale: 1.00, yaw: -Math.PI * 2.0 + 0.31, pitch: -0.05, roll: -0.05, eyeShiftX: -0.05, eyeShiftY: 0.035, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 1.0, squint: 0.0, jumpY: 0.0 } },
954
- { t: 3.48, label: 'look-right-settle', ease: 'easeInOutQuad', pose: { scaleX: 1.0, scaleY: 1.0, visible: true, scale: 1.0, yaw: -Math.PI * 2.0 + 0.31, pitch: -0.05, roll: -0.05, eyeShiftX: -0.05, eyeShiftY: 0.035, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
955
- { t: 3.64, label: 'look-right-settle', ease: 'linear', pose: { scale: 1.0, scaleX: 1.0, scaleY: 1.0, visible: true, scale: 1.0, yaw: -Math.PI * 2.0 + 0.31, pitch: -0.05, roll: -0.05, eyeShiftX: -0.05, eyeShiftY: 0.035, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
956
- { t: 3.94, label: 'turn-to-lookup', ease: 'easeInOutQuad', pose: { visible: true, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -Math.PI * 2.0 - 0.78, pitch: -0.21, roll: 0.0, eyeShiftX: -0.10, eyeShiftY: 0.035, eyeScaleX: 0.95, eyeScaleY: 0.88, eyeGap: 0.22, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
957
- { t: 4.28, label: 'lookup-still-blink-2', ease: 'linear', pose: { visible: true, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -Math.PI * 2.0 - 0.78, pitch: -0.21, roll: 0.0, eyeShiftX: -0.10, eyeShiftY: 0.035, eyeScaleX: 0.95, eyeScaleY: 0.88, eyeGap: 0.22, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
958
- { t: 4.75, label: 'transition-to-right', ease: 'easeInOutQuad', pose: { visible: true, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -Math.PI * 2.0 + 0.31, pitch: -0.05, roll: -0.05, eyeShiftX: -0.05, eyeShiftY: 0.035, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
959
- { t: 6.12, label: 'look-right-curious', ease: 'linear', pose: { visible: true, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -Math.PI * 2.0 + 0.31, pitch: -0.05, roll: -0.05, eyeShiftX: -0.05, eyeShiftY: 0.035, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
960
- { t: 6.24, label: 'anticipation-squash', ease: 'easeInOutQuad', pose: { visible: true, scale: 1.0, scaleX: 1.16, scaleY: 0.85, yaw: -Math.PI * 2.0 + 0.28, pitch: -0.02, roll: -0.02, eyeShiftX: -0.05, eyeShiftY: 0.025, eyeScaleX: 1.10, eyeScaleY: 0.88, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: -0.035 } },
961
- { t: 6.36, label: 'anticipation-rebound', ease: 'easeInOutQuad', pose: { visible: true, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -Math.PI * 2.0 + 0.35, pitch: -0.04, roll: -0.04, eyeShiftX: -0.05, eyeShiftY: 0.035, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.02 } },
962
- { t: 6.52, label: 'exit-spin-right', ease: 'easeInOutQuad', pose: { visible: true, scale: 0.94, scaleX: 1.0, scaleY: 1.0, yaw: -Math.PI * 2.0 + 1.45, pitch: -0.03, roll: -0.02, eyeShiftX: -0.05, eyeShiftY: 0.035, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
963
- { t: 6.72, label: 'exit-spin-right', ease: 'easeInOutQuad', pose: { visible: true, scale: 0.45, scaleX: 1.0, scaleY: 1.0, yaw: -Math.PI * 2.0 + 2.55, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
964
- { t: 6.88, label: 'exit-spin-right', ease: 'easeInOutQuad', pose: { visible: false, scale: 0.0, scaleX: 1.0, scaleY: 1.0, yaw: -Math.PI * 2.0 + 3.40, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } },
965
- { t: 20.783, label: 'idle', ease: 'linear', pose: { scaleX: 1.0, scaleY: 1.0, visible: false, scale: 0.0, yaw: -Math.PI * 2.0 + 3.40, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, eyeGap: 0.27, bulge: 0.0, squint: 0.0, jumpY: 0.0 } }
966
- ]);
967
-
968
- var bot5Blinks = new BlinkTrack([
969
- { start: 3.73, duration: 0.12, maxSquint: 0.95 },
970
- { start: 4.06, duration: 0.12, maxSquint: 0.95 }
971
- ]);
972
- var bot5Dots = new DotGridRig(38.0, 10.1);
973
-
974
- function getBot5State(time) {
975
- var t = ((time % LOOP) + LOOP) % LOOP;
976
- var res = bot5Timeline.evaluate(t);
977
- var pose = res.pose;
978
- pose.squint = bot5Blinks.evaluate(t);
979
- pose.y = (pose.jumpY || 0.0);
980
-
981
- if (t >= 4.75 && t < 6.12) {
982
- pose.scale += Math.sin((t - 4.75) * 2.5) * 0.012;
983
- }
984
- var dots = bot5Dots.evaluate(t, pose.scale, pose.visible);
985
-
986
- return {
987
- botId: 5,
988
- type: 'bot5',
989
- label: res.label,
990
- dots: dots,
991
- bot: {
992
- visible: pose.visible,
993
- scale: pose.scale,
994
- scaleX: pose.scaleX,
995
- scaleY: pose.scaleY,
996
- x: pose.x || 0.0,
997
- y: pose.y,
998
- yaw: pose.yaw,
999
- pitch: pose.pitch,
1000
- roll: pose.roll,
1001
- eyeShiftX: pose.eyeShiftX,
1002
- eyeShiftY: pose.eyeShiftY,
1003
- eyeScaleX: pose.eyeScaleX,
1004
- eyeScaleY: pose.eyeScaleY,
1005
- eyeGap: pose.eyeGap,
1006
- bulge: pose.bulge,
1007
- squint: pose.squint,
1008
- bodyColor: 0x222126,
1009
- eyeColor: 0xffffff
1010
- }
1011
- };
1012
- }
1013
-
1014
- // --- #6 Ghost Trail (幽灵分身) ---
1015
- var bot6Timeline = new PoseTimeline([
1016
- { t: 0.00, label: 'ghost-blink-1', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1017
- { t: 0.40, label: 'giant-bulge-1-start', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.05, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.04, bulge: 0.6, jumpY: 0.0 } },
1018
- { t: 0.65, label: 'giant-bulge-1-peak', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.05, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.08, bulge: 1.25, jumpY: 0.0 } },
1019
- { t: 0.95, label: 'single-solid-1', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1020
- { t: 2.40, label: 'single-solid-1', ease: 'linear', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1021
- { t: 3.10, label: 'lookup-left-1', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.42, pitch: -0.04, roll: 0.02, eyeShiftX: -0.06, eyeShiftY: 0.02, bulge: 0.0, jumpY: 0.0 } },
1022
- { t: 3.35, label: 'squash-prep-1', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 0.92, scaleX: 1.08, scaleY: 0.92, yaw: -0.40, pitch: -0.03, roll: 0.01, eyeShiftX: -0.055, eyeShiftY: -0.02, bulge: 0.0, jumpY: -0.01 } },
1023
- { t: 3.65, label: 'purple-solo-split-1', ease: 'easeInOutQuad', pose: { splitL: 1.0, splitR: 0.0, scale: 0.46, scaleX: 1.0, scaleY: 1.0, yaw: -0.38, pitch: -0.02, roll: -0.03, eyeShiftX: -0.05, eyeShiftY: 0.01, bulge: 0.0, jumpY: 0.0 } },
1024
- { t: 3.95, label: 'look-right-prep', ease: 'easeInOutQuad', pose: { splitL: 1.0, splitR: 0.0, scale: 0.46, scaleX: 1.0, scaleY: 1.0, yaw: 0.38, pitch: -0.02, roll: 0.02, eyeShiftX: 0.05, eyeShiftY: 0.01, bulge: 0.0, jumpY: 0.0 } },
1025
- { t: 4.20, label: 'cyan-solo-split-1', ease: 'easeInOutQuad', pose: { splitL: 1.0, splitR: 1.0, scale: 0.46, scaleX: 1.0, scaleY: 1.0, yaw: 0.34, pitch: 0.0, roll: 0.0, eyeShiftX: 0.04, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1026
- { t: 4.50, label: 'triple-dance-1', ease: 'easeInOutQuad', pose: { splitL: 1.0, splitR: 1.0, scale: 0.46, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1027
- { t: 7.40, label: 'triple-dance-1', ease: 'linear', pose: { splitL: 1.0, splitR: 1.0, scale: 0.46, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1028
- { t: 7.80, label: 'ghost-merge-1', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1029
- { t: 8.50, label: 'single-solid-1-end', ease: 'linear', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1030
- { t: 8.50, label: 'ghost-blink-2', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1031
- { t: 8.90, label: 'giant-bulge-2-start', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.05, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.04, bulge: 0.6, jumpY: 0.0 } },
1032
- { t: 9.15, label: 'giant-bulge-2-peak', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.05, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.08, bulge: 1.25, jumpY: 0.0 } },
1033
- { t: 9.45, label: 'single-solid-2', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1034
- { t: 10.90, label: 'single-solid-2', ease: 'linear', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1035
- { t: 11.60, label: 'lookup-left-2', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.42, pitch: -0.04, roll: 0.02, eyeShiftX: -0.06, eyeShiftY: 0.02, bulge: 0.0, jumpY: 0.0 } },
1036
- { t: 11.85, label: 'squash-prep-2', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 0.92, scaleX: 1.08, scaleY: 0.92, yaw: -0.40, pitch: -0.03, roll: 0.01, eyeShiftX: -0.055, eyeShiftY: -0.02, bulge: 0.0, jumpY: -0.01 } },
1037
- { t: 12.15, label: 'purple-solo-split-2', ease: 'easeInOutQuad', pose: { splitL: 1.0, splitR: 0.0, scale: 0.46, scaleX: 1.0, scaleY: 1.0, yaw: -0.38, pitch: -0.02, roll: -0.03, eyeShiftX: -0.05, eyeShiftY: 0.01, bulge: 0.0, jumpY: 0.0 } },
1038
- { t: 12.45, label: 'look-right-prep-2', ease: 'easeInOutQuad', pose: { splitL: 1.0, splitR: 0.0, scale: 0.46, scaleX: 1.0, scaleY: 1.0, yaw: 0.38, pitch: -0.02, roll: 0.02, eyeShiftX: 0.05, eyeShiftY: 0.01, bulge: 0.0, jumpY: 0.0 } },
1039
- { t: 12.70, label: 'cyan-solo-split-2', ease: 'easeInOutQuad', pose: { splitL: 1.0, splitR: 1.0, scale: 0.46, scaleX: 1.0, scaleY: 1.0, yaw: 0.34, pitch: 0.0, roll: 0.0, eyeShiftX: 0.04, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1040
- { t: 13.00, label: 'triple-dance-2', ease: 'easeInOutQuad', pose: { splitL: 1.0, splitR: 1.0, scale: 0.46, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1041
- { t: 15.90, label: 'triple-dance-2', ease: 'linear', pose: { splitL: 1.0, splitR: 1.0, scale: 0.46, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1042
- { t: 16.30, label: 'ghost-merge-2', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1043
- { t: 17.00, label: 'single-solid-2-end', ease: 'linear', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1044
- { t: 17.00, label: 'ghost-blink-3', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1045
- { t: 17.40, label: 'giant-bulge-3-start', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.05, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.04, bulge: 0.6, jumpY: 0.0 } },
1046
- { t: 17.65, label: 'giant-bulge-3-peak', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.05, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.08, bulge: 1.25, jumpY: 0.0 } },
1047
- { t: 17.95, label: 'single-solid-3', ease: 'easeInOutQuad', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } },
1048
- { t: 20.783, label: 'single-solid-3', ease: 'linear', pose: { splitL: 0.0, splitR: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, bulge: 0.0, jumpY: 0.0 } }
1049
- ]);
1050
-
1051
- var bot6Blinks = new BlinkTrack([
1052
- { start: 0.00, duration: 0.25, maxSquint: 1.0 },
1053
- { start: 1.05, duration: 0.12, maxSquint: 0.95 },
1054
- { start: 2.70, duration: 0.12, maxSquint: 0.95 },
1055
- { start: 3.20, duration: 0.14, maxSquint: 0.95 },
1056
- { start: 8.50, duration: 0.25, maxSquint: 1.0 },
1057
- { start: 9.55, duration: 0.12, maxSquint: 0.95 },
1058
- { start: 11.20, duration: 0.12, maxSquint: 0.95 },
1059
- { start: 11.70, duration: 0.14, maxSquint: 0.95 },
1060
- { start: 17.00, duration: 0.25, maxSquint: 1.0 },
1061
- { start: 18.05, duration: 0.12, maxSquint: 0.95 },
1062
- { start: 19.50, duration: 0.12, maxSquint: 0.95 }
1063
- ]);
1064
-
1065
- function getBot6State(time) {
1066
- var t = ((time % LOOP) + LOOP) % LOOP;
1067
- var res = bot6Timeline.evaluate(t);
1068
- var pose = res.pose;
1069
- var squint = bot6Blinks.evaluate(t);
1070
-
1071
- var splitL = pose.splitL || 0.0;
1072
- var splitR = pose.splitR || 0.0;
1073
- var maxSplit = Math.max(splitL, splitR);
1074
-
1075
- var omegaV = 3.649 * Math.PI * 2.0;
1076
- var omegaH = 1.820 * Math.PI * 2.0;
1077
- var waveY = Math.sin(t * omegaV) * 0.015 * maxSplit;
1078
- var waveYL = Math.sin((t + 0.12) * omegaV) * 0.015 * splitL;
1079
- var waveYR = Math.sin((t - 0.12) * omegaV) * 0.015 * splitR;
1080
-
1081
- var swayXC = Math.sin(t * omegaH) * 0.0220 * maxSplit;
1082
- var swayXL = Math.sin((t + 0.12) * omegaH) * 0.0220 * splitL;
1083
- var swayXR = Math.sin((t - 0.12) * omegaH) * 0.0220 * splitR;
1084
-
1085
- var centerShiftX = (splitL > 0.01 && splitR < 0.5) ? +0.018 * splitL : ((splitR > 0.01 && splitL < 0.5) ? -0.018 * splitR : 0.0);
1086
- var sepDist = 0.258;
1087
- var currentScale = pose.scale;
1088
-
1089
- var botCenter = {
1090
- visible: true,
1091
- scale: currentScale,
1092
- scaleX: pose.scaleX || 1.0,
1093
- scaleY: pose.scaleY || 1.0,
1094
- x: swayXC + centerShiftX,
1095
- y: (pose.jumpY || 0.0) + waveY,
1096
- yaw: pose.yaw || 0.0,
1097
- pitch: pose.pitch || 0.0,
1098
- roll: pose.roll || 0.0,
1099
- eyeShiftX: pose.eyeShiftX || 0.0,
1100
- eyeShiftY: pose.eyeShiftY || 0.0,
1101
- eyeScaleX: 1.0,
1102
- eyeScaleY: 1.0,
1103
- eyeGap: 0.27,
1104
- bulge: pose.bulge || 0.0,
1105
- squint: squint,
1106
- bodyColor: 0x222126,
1107
- eyeColor: 0xffffff,
1108
- splitL: splitL,
1109
- splitR: splitR
1110
- };
1111
-
1112
- var spawnXL = -(0.11 + (sepDist - 0.11) * splitL);
1113
- var ghostL = {
1114
- visible: splitL > 0.01,
1115
- scale: 0.46 * splitL,
1116
- scaleX: 1.0,
1117
- scaleY: 1.0,
1118
- x: spawnXL + swayXL,
1119
- y: waveYL,
1120
- yaw: (pose.yaw || 0.0) * 0.5,
1121
- pitch: (pose.pitch || 0.0) * 0.5,
1122
- roll: (pose.roll || 0.0) * 0.5 - 0.03 * splitL,
1123
- eyeShiftX: 0.0,
1124
- eyeShiftY: 0.0,
1125
- eyeScaleX: 0.85,
1126
- eyeScaleY: 0.85,
1127
- eyeGap: 0.27,
1128
- bulge: 0.0,
1129
- squint: squint,
1130
- bodyColor: 0x8229cc,
1131
- eyeColor: 0xe8cbfa
1132
- };
1133
-
1134
- var spawnXR = +(0.11 + (sepDist - 0.11) * splitR);
1135
- var ghostR = {
1136
- visible: splitR > 0.01,
1137
- scale: 0.46 * splitR,
1138
- scaleX: 1.0,
1139
- scaleY: 1.0,
1140
- x: spawnXR + swayXR,
1141
- y: waveYR,
1142
- yaw: (pose.yaw || 0.0) * 0.5,
1143
- pitch: (pose.pitch || 0.0) * 0.5,
1144
- roll: (pose.roll || 0.0) * 0.5 + 0.03 * splitR,
1145
- eyeShiftX: 0.0,
1146
- eyeShiftY: 0.0,
1147
- eyeScaleX: 0.85,
1148
- eyeScaleY: 0.85,
1149
- eyeGap: 0.27,
1150
- bulge: 0.0,
1151
- squint: squint,
1152
- bodyColor: 0x47e4ad,
1153
- eyeColor: 0xaff5dc
1154
- };
1155
-
1156
- return {
1157
- botId: 6,
1158
- type: 'bot6',
1159
- label: res.label,
1160
- botCenter: botCenter,
1161
- ghostL: ghostL,
1162
- ghostR: ghostR,
1163
- splitL: splitL,
1164
- splitR: splitR,
1165
- dots: []
1166
- };
1167
- }
1168
-
1169
- // --- #7 Satellite (环绕卫星) ---
1170
- var bot7Timeline = new PoseTimeline([
1171
- { t: 0.00, label: 'solid-upright', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 0.20, bulge: 0.0, jumpY: 0.0, squint: 0.75, showEyes: true } },
1172
- { t: 0.06, label: 'loop-blink-open', ease: 'linear', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1173
- { t: 1.30, label: 'solid-idle-1', ease: 'linear', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1174
- { t: 1.45, label: 'curious-look-left-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.26, pitch: 0.0, roll: -0.14, eyeShiftX: -0.045, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1175
- { t: 2.00, label: 'curious-look-left-1', ease: 'linear', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.26, pitch: 0.0, roll: -0.14, eyeShiftX: -0.045, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1176
- { t: 2.12, label: 'squash-prep-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.05, scaleY: 0.95, yaw: 0.0, pitch: 0.01, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: -0.01, eyeScaleX: 1.05, eyeScaleY: 0.95, bulge: 0.0, jumpY: -0.008, squint: 0.0, showEyes: true } },
1177
- { t: 2.24, label: 'anticipation-squash-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.22, scaleY: 0.78, yaw: 0.0, pitch: 0.02, roll: 0.0, eyeShiftX: -0.015, eyeShiftY: -0.025, eyeScaleX: 1.18, eyeScaleY: 0.75, bulge: 0.0, jumpY: -0.024, squint: 0.0, showEyes: true } },
1178
- { t: 2.40, label: 'anticipation-stretch-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 0.96, scaleX: 0.88, scaleY: 1.18, yaw: 0.0, pitch: -0.04, roll: 0.36, eyeShiftX: -0.020, eyeShiftY: 0.035, eyeScaleX: 0.92, eyeScaleY: 1.12, bulge: 0.0, jumpY: 0.035, squint: 0.0, showEyes: true } },
1179
- { t: 2.52, label: 'collapse-shrink-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 0.65, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.02, roll: 0.08, eyeShiftX: 0.0, eyeShiftY: 0.01, eyeScaleX: 0.95, eyeScaleY: 0.95, bulge: 0.0, jumpY: 0.015, squint: 0.0, showEyes: false } },
1180
- { t: 2.56, label: 'collapse-core-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 0.52, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: false } },
1181
- { t: 2.80, label: 'satellite-burst-1', ease: 'linear', pose: { ringExpand: 1.0, scale: 0.52, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.02, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1182
- { t: 7.04, label: 'satellite-orbit-1', ease: 'linear', pose: { ringExpand: 1.0, scale: 0.52, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.02, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1183
- { t: 7.30, label: 'suction-absorb-1', ease: 'linear', pose: { ringExpand: 0.0, scale: 0.72, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: -0.02, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: -0.005, squint: 0.0, showEyes: false } },
1184
- { t: 7.46, label: 'expand-shoot-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 0.88, scaleY: 1.18, yaw: 0.0, pitch: -0.03, roll: -0.32, eyeShiftX: 0.02, eyeShiftY: 0.035, eyeScaleX: 0.95, eyeScaleY: 1.10, bulge: 0.0, jumpY: 0.035, squint: 0.0, showEyes: true } },
1185
- { t: 7.60, label: 'expand-land-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.12, scaleY: 0.90, yaw: 0.0, pitch: 0.0, roll: -0.04, eyeShiftX: -0.02, eyeShiftY: -0.01, eyeScaleX: 1.05, eyeScaleY: 0.95, bulge: 0.0, jumpY: -0.014, squint: 0.0, showEyes: true } },
1186
- { t: 7.72, label: 'settle-left-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.12, pitch: 0.0, roll: 0.0, eyeShiftX: -0.035, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1187
- { t: 7.86, label: 'sleepy-prep-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: -0.02, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1188
- { t: 7.98, label: 'sleepy-slits-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: -0.08, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 0.88, eyeScaleY: 0.12, bulge: 0.0, jumpY: 0.0, squint: 0.95, showEyes: true } },
1189
- { t: 8.06, label: 'sleepy-slits-hold-1', ease: 'linear', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: -0.08, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 0.88, eyeScaleY: 0.12, bulge: 0.0, jumpY: 0.0, squint: 0.95, showEyes: true } },
1190
- { t: 8.18, label: 'curious-look-right-1', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.32, pitch: -0.04, roll: 0.02, eyeShiftX: 0.048, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1191
- { t: 10.00, label: 'curious-look-right-1', ease: 'linear', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.32, pitch: -0.04, roll: 0.02, eyeShiftX: 0.048, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1192
- { t: 10.12, label: 'squash-prep-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.06, scaleY: 0.94, yaw: 0.08, pitch: 0.01, roll: 0.0, eyeShiftX: 0.01, eyeShiftY: -0.01, eyeScaleX: 1.05, eyeScaleY: 0.95, bulge: 0.0, jumpY: -0.008, squint: 0.0, showEyes: true } },
1193
- { t: 10.23, label: 'anticipation-squash-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.22, scaleY: 0.78, yaw: 0.0, pitch: 0.02, roll: 0.0, eyeShiftX: -0.015, eyeShiftY: -0.025, eyeScaleX: 1.18, eyeScaleY: 0.75, bulge: 0.0, jumpY: -0.024, squint: 0.0, showEyes: true } },
1194
- { t: 10.40, label: 'anticipation-stretch-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 0.96, scaleX: 0.88, scaleY: 1.18, yaw: 0.0, pitch: -0.04, roll: 0.36, eyeShiftX: -0.020, eyeShiftY: 0.035, eyeScaleX: 0.92, eyeScaleY: 1.12, bulge: 0.0, jumpY: 0.035, squint: 0.0, showEyes: true } },
1195
- { t: 10.52, label: 'collapse-shrink-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 0.65, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.02, roll: 0.08, eyeShiftX: 0.0, eyeShiftY: 0.01, eyeScaleX: 0.95, eyeScaleY: 0.95, bulge: 0.0, jumpY: 0.015, squint: 0.0, showEyes: false } },
1196
- { t: 10.56, label: 'collapse-core-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 0.52, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: false } },
1197
- { t: 10.80, label: 'satellite-burst-2', ease: 'linear', pose: { ringExpand: 1.0, scale: 0.52, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.02, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1198
- { t: 15.04, label: 'satellite-orbit-2', ease: 'linear', pose: { ringExpand: 1.0, scale: 0.52, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.02, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1199
- { t: 15.30, label: 'suction-absorb-2', ease: 'linear', pose: { ringExpand: 0.0, scale: 0.72, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: -0.02, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: -0.005, squint: 0.0, showEyes: false } },
1200
- { t: 15.46, label: 'expand-shoot-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 0.88, scaleY: 1.18, yaw: 0.0, pitch: -0.03, roll: -0.32, eyeShiftX: 0.02, eyeShiftY: 0.035, eyeScaleX: 0.95, eyeScaleY: 1.10, bulge: 0.0, jumpY: 0.035, squint: 0.0, showEyes: true } },
1201
- { t: 15.62, label: 'expand-land-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.12, scaleY: 0.90, yaw: 0.0, pitch: 0.0, roll: -0.04, eyeShiftX: -0.02, eyeShiftY: -0.01, eyeScaleX: 1.05, eyeScaleY: 0.95, bulge: 0.0, jumpY: -0.014, squint: 0.0, showEyes: true } },
1202
- { t: 15.72, label: 'settle-left-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: -0.12, pitch: 0.0, roll: 0.0, eyeShiftX: -0.035, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1203
- { t: 15.86, label: 'sleepy-prep-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: -0.02, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1204
- { t: 15.98, label: 'sleepy-slits-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: -0.08, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 0.88, eyeScaleY: 0.12, bulge: 0.0, jumpY: 0.0, squint: 0.95, showEyes: true } },
1205
- { t: 16.06, label: 'sleepy-slits-hold-2', ease: 'linear', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: -0.08, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 0.88, eyeScaleY: 0.12, bulge: 0.0, jumpY: 0.0, squint: 0.95, showEyes: true } },
1206
- { t: 16.18, label: 'curious-look-right-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.32, pitch: -0.04, roll: 0.02, eyeShiftX: 0.048, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1207
- { t: 16.24, label: 'glance-blink-prep-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.32, pitch: -0.04, roll: 0.02, eyeShiftX: 0.048, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1208
- { t: 16.32, label: 'glance-blink-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.32, pitch: -0.04, roll: 0.02, eyeShiftX: 0.048, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 0.12, bulge: 0.0, jumpY: 0.0, squint: 0.85, showEyes: true } },
1209
- { t: 16.40, label: 'glance-blink-open-2', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.32, pitch: -0.04, roll: 0.02, eyeShiftX: 0.048, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1210
- { t: 17.80, label: 'curious-look-right-2', ease: 'linear', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.0, scaleY: 1.0, yaw: 0.32, pitch: -0.04, roll: 0.02, eyeShiftX: 0.048, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1211
- { t: 18.12, label: 'squash-prep-3', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.06, scaleY: 0.94, yaw: 0.28, pitch: 0.01, roll: 0.0, eyeShiftX: 0.042, eyeShiftY: -0.01, eyeScaleX: 1.05, eyeScaleY: 0.95, bulge: 0.0, jumpY: -0.008, squint: 0.0, showEyes: true } },
1212
- { t: 18.22, label: 'anticipation-squash-3', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 1.0, scaleX: 1.22, scaleY: 0.78, yaw: 0.22, pitch: 0.02, roll: 0.0, eyeShiftX: 0.040, eyeShiftY: -0.025, eyeScaleX: 1.18, eyeScaleY: 0.75, bulge: 0.0, jumpY: -0.024, squint: 0.0, showEyes: true } },
1213
- { t: 18.38, label: 'anticipation-stretch-3', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 0.96, scaleX: 0.88, scaleY: 1.18, yaw: 0.0, pitch: -0.04, roll: 0.36, eyeShiftX: -0.020, eyeShiftY: 0.035, eyeScaleX: 0.92, eyeScaleY: 1.12, bulge: 0.0, jumpY: 0.035, squint: 0.0, showEyes: true } },
1214
- { t: 18.50, label: 'collapse-shrink-3', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 0.65, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.02, roll: 0.08, eyeShiftX: 0.0, eyeShiftY: 0.01, eyeScaleX: 0.95, eyeScaleY: 0.95, bulge: 0.0, jumpY: 0.015, squint: 0.0, showEyes: false } },
1215
- { t: 18.56, label: 'collapse-core-3', ease: 'easeInOutQuad', pose: { ringExpand: 0.0, scale: 0.52, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: 0.0, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.0, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: false } },
1216
- { t: 18.80, label: 'satellite-burst-3', ease: 'linear', pose: { ringExpand: 1.0, scale: 0.52, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.02, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } },
1217
- { t: 20.783, label: 'satellite-orbit-3', ease: 'linear', pose: { ringExpand: 1.0, scale: 0.52, scaleX: 1.0, scaleY: 1.0, yaw: 0.0, pitch: -0.02, roll: 0.0, eyeShiftX: 0.0, eyeShiftY: 0.01, eyeScaleX: 1.0, eyeScaleY: 1.0, bulge: 0.0, jumpY: 0.0, squint: 0.0, showEyes: true } }
1218
- ]);
1219
-
1220
- var SATELLITE_RING_OFFSETS = [
1221
- { x: 0, y: -46.0 },
1222
- { x: 45.4, y: -46.0 },
1223
- { x: 45.4, y: 0 },
1224
- { x: 45.4, y: 46.0 },
1225
- { x: 0, y: 46.0 },
1226
- { x: -45.4, y: 46.0 },
1227
- { x: -45.4, y: 0 },
1228
- { x: -45.4, y: -46.0 }
1229
- ];
1230
-
1231
- var ORBIT_PERIOD = 3.600;
1232
- var CAM_YAW_AMP = 0.45;
1233
- var CAM_PITCH_AMP = 0.35;
1234
- var CAM_PITCH_NEUTRAL = -0.10;
1235
- var CAM_AZIMUTH_OFFSET = -0.118;
1236
- var CAM_ELEVATION_OFFSET = 0.146;
1237
-
1238
- function getBot7State(time) {
1239
- var t = ((time % LOOP) + LOOP) % LOOP;
1240
- var res = bot7Timeline.evaluate(t);
1241
- var pose = res.pose;
1242
- var ringExpand = pose.ringExpand;
1243
-
1244
- var tOrbitStart = 3.20;
1245
- if (t >= 17.0) {
1246
- tOrbitStart = 19.20;
1247
- } else if (t >= 9.0) {
1248
- tOrbitStart = 11.20;
1249
- }
1250
-
1251
- var tOrbit = ((t - tOrbitStart) % ORBIT_PERIOD + ORBIT_PERIOD) % ORBIT_PERIOD;
1252
- var waveAngle = - (tOrbit / ORBIT_PERIOD) * Math.PI * 2 - Math.PI / 2;
1253
-
1254
- var targetDirX = Math.cos(waveAngle);
1255
- var targetDirY = Math.sin(waveAngle);
1256
-
1257
- var camYaw = targetDirX * CAM_YAW_AMP * ringExpand;
1258
- var camPitch = (CAM_PITCH_NEUTRAL - targetDirY * CAM_PITCH_AMP) * ringExpand;
1259
-
1260
- var trackingYaw = camYaw + CAM_AZIMUTH_OFFSET * ringExpand;
1261
- var trackingPitch = camPitch - CAM_ELEVATION_OFFSET * ringExpand;
1262
-
1263
- var hoverY = Math.sin((tOrbit / ORBIT_PERIOD) * 2 * Math.PI) * 0.006 * ringExpand;
1264
- var hoverYPx = hoverY * 500.0;
1265
- var dynamicRoll = targetDirX * 0.04 * ringExpand;
1266
-
1267
- var dots = [];
1268
- if (ringExpand > 0.001) {
1269
- var dotDist = (35.0 + 10.4 * ringExpand) / 45.4;
1270
- for (var i = 0; i < 8; i++) {
1271
- var off = SATELLITE_RING_OFFSETS[i];
1272
- var dotAngle = Math.atan2(-off.y, off.x);
1273
- var diff = Math.cos(waveAngle - dotAngle);
1274
- var pulse = Math.pow(Math.max(0, diff), 6);
1275
- var r = ringExpand * (7.0 + pulse * 4.5);
1276
- dots.push({
1277
- x: off.x * dotDist,
1278
- y: off.y * dotDist - hoverYPx,
1279
- r: r,
1280
- visible: true
1281
- });
1282
- }
1283
- }
1284
-
1285
- var bot = {
1286
- visible: true,
1287
- scale: pose.scale,
1288
- scaleX: pose.scaleX,
1289
- scaleY: pose.scaleY,
1290
- x: 0.0,
1291
- y: (pose.jumpY || 0.0) + hoverY,
1292
- yaw: (pose.yaw || 0.0) + trackingYaw,
1293
- pitch: (pose.pitch || 0.0) + trackingPitch,
1294
- roll: (pose.roll || 0.0) + dynamicRoll,
1295
- eyeShiftX: pose.eyeShiftX || 0.0,
1296
- eyeShiftY: pose.eyeShiftY || 0.0,
1297
- eyeScaleX: pose.eyeScaleX,
1298
- eyeScaleY: pose.eyeScaleY,
1299
- eyeGap: 0.27,
1300
- bulge: pose.bulge,
1301
- squint: pose.squint || 0.0,
1302
- showEyes: pose.showEyes !== false,
1303
- bodyColor: 0x222126,
1304
- eyeColor: 0xffffff
1305
- };
1306
-
1307
- return { botId: 7, type: 'bot7', label: res.label, bot: bot, dots: dots };
1308
- }
1309
-
1310
- /* =========================================================================
1311
- 4. Bot Catalog Registry & State Dispatcher
1312
- ========================================================================= */
1313
- var BOTS = [
1314
- { id: 1, key: 'sentry', name: 'Sentry', title: '哨兵', desc: '逐行专注扫读、机灵侧倾 (代码审视/终端监控)', stateFn: getBot1State },
1315
- { id: 2, key: 'attitude', name: 'Attitude', title: '傲娇小怪', desc: '3D后空翻、单侧挑眉与犀利聚焦 (AI拟人化助手/成功反馈)', stateFn: getBot2State },
1316
- { id: 3, key: 'chameleon', name: 'Chameleon', title: '动感变色龙', desc: '240bpm 高频街舞摇摆、12色轮转 (音乐播放器/动感加载)', stateFn: getBot3State },
1317
- { id: 4, key: 'observer', name: 'Observer', title: '屏读观察者', desc: '纯水平左-中-右栅格阅读扫读 (屏幕扫描/数据同步)', stateFn: getBot4State },
1318
- { id: 5, key: 'cube', name: 'Cube & Grid', title: '方块与点阵', desc: '3x3呼吸点阵破土自旋跳跃、大眼暴胀 (启动/生成态/弹窗)', stateFn: getBot5State },
1319
- { id: 6, key: 'ghost', name: 'Ghost Trail', title: '幽灵分身', desc: '身后诞生紫青双分身、蛇形浮游共舞 (多线程运算/集群协同)', stateFn: getBot6State },
1320
- { id: 7, key: 'satellite', name: 'Satellite', title: '环绕卫星', desc: '核心塌陷蓄力、8卫星逆时针公转与3D注视 (网络加载/能量缓冲)', stateFn: getBot7State }
1321
- ];
1322
-
1323
- function resolveBotId(idOrKey) {
1324
- if (typeof idOrKey === 'number') return idOrKey;
1325
- if (typeof idOrKey === 'string') {
1326
- var lower = idOrKey.toLowerCase().trim();
1327
- var num = parseInt(lower.replace('#', ''), 10);
1328
- if (!isNaN(num) && num >= 1 && num <= 7) return num;
1329
- for (var i = 0; i < BOTS.length; i++) {
1330
- if (BOTS[i].key === lower || BOTS[i].name.toLowerCase() === lower) {
1331
- return BOTS[i].id;
1332
- }
1333
- }
1334
- }
1335
- return 1;
1336
- }
1337
-
1338
- function getBotState(botId, time) {
1339
- var id = resolveBotId(botId);
1340
- switch (id) {
1341
- case 1: return getBot1State(time);
1342
- case 2: return getBot2State(time);
1343
- case 3: return getBot3State(time);
1344
- case 4: return getBot4State(time);
1345
- case 5: return getBot5State(time);
1346
- case 6: return getBot6State(time);
1347
- case 7: return getBot7State(time);
1348
- default: return getBot1State(time);
1349
- }
1350
- }
1351
-
1352
- /* =========================================================================
1353
- 5. High-Level Mount Renderer & Player Controller
1354
- ========================================================================= */
1355
- var stageCounter = 0;
1356
-
1357
- function mount(container, options) {
1358
- if (!container) {
1359
- throw new Error('[OpenBotMotion] mount requires a valid DOM element.');
1360
- }
1361
- options = options || {};
1362
-
1363
- var activeBotId = resolveBotId(options.bot !== undefined ? options.bot : 1);
1364
- var size = options.size !== undefined ? options.size : 280;
1365
- var autoplay = options.autoplay !== undefined ? options.autoplay : true;
1366
- var loop = options.loop !== undefined ? options.loop : true;
1367
- var speed = options.speed !== undefined ? options.speed : 1.0;
1368
- var onFrame = typeof options.onFrame === 'function' ? options.onFrame : null;
1369
-
1370
- container.innerHTML = '';
1371
- var uid = ++stageCounter;
1372
- var svgNS = 'http://www.w3.org/2000/svg';
1373
-
1374
- var svg = document.createElementNS(svgNS, 'svg');
1375
- svg.setAttribute('class', 'open-bot-motion-svg');
1376
- svg.setAttribute('viewBox', '-140 -140 280 280');
1377
- svg.setAttribute('width', typeof size === 'number' ? (size + 'px') : size);
1378
- svg.setAttribute('height', typeof size === 'number' ? (size + 'px') : size);
1379
- svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
1380
- container.appendChild(svg);
1381
-
1382
- var defs = document.createElementNS(svgNS, 'defs');
1383
- svg.appendChild(defs);
1384
-
1385
- var filter = document.createElementNS(svgNS, 'filter');
1386
- filter.setAttribute('id', 'obm-gooey-' + uid);
1387
- filter.setAttribute('x', '-50%');
1388
- filter.setAttribute('y', '-50%');
1389
- filter.setAttribute('width', '200%');
1390
- filter.setAttribute('height', '200%');
1391
- filter.innerHTML =
1392
- '<feGaussianBlur in="SourceGraphic" stdDeviation="5.5" result="blur" />' +
1393
- '<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="goo" />' +
1394
- '<feComposite in="SourceGraphic" in2="goo" operator="atop" />';
1395
- defs.appendChild(filter);
1396
-
1397
- function createClipDef(clipId, pathId) {
1398
- var cp = document.createElementNS(svgNS, 'clipPath');
1399
- cp.setAttribute('id', clipId);
1400
- var p = document.createElementNS(svgNS, 'path');
1401
- p.setAttribute('id', pathId);
1402
- cp.appendChild(p);
1403
- defs.appendChild(cp);
1404
- return p;
1405
- }
1406
-
1407
- var clipPathCenter = createClipDef('obm-clip-center-' + uid, 'obm-cpp-center-' + uid);
1408
- var clipPathGhostL = createClipDef('obm-clip-ghostL-' + uid, 'obm-cpp-ghostL-' + uid);
1409
- var clipPathGhostR = createClipDef('obm-clip-ghostR-' + uid, 'obm-cpp-ghostR-' + uid);
1410
-
1411
- var dotsLayer = document.createElementNS(svgNS, 'g');
1412
- dotsLayer.setAttribute('class', 'dots-layer');
1413
- svg.appendChild(dotsLayer);
1414
-
1415
- var botLayer = document.createElementNS(svgNS, 'g');
1416
- botLayer.setAttribute('class', 'bot-layer');
1417
- svg.appendChild(botLayer);
1418
-
1419
- var bodiesLayer = document.createElementNS(svgNS, 'g');
1420
- bodiesLayer.setAttribute('class', 'bodies-layer');
1421
- botLayer.appendChild(bodiesLayer);
1422
-
1423
- var eyesLayer = document.createElementNS(svgNS, 'g');
1424
- eyesLayer.setAttribute('class', 'eyes-layer');
1425
- botLayer.appendChild(eyesLayer);
1426
-
1427
- function createBotNode(clipId, defaultColor) {
1428
- var bodyPath = document.createElementNS(svgNS, 'path');
1429
- bodyPath.setAttribute('fill', defaultColor);
1430
- bodiesLayer.appendChild(bodyPath);
1431
-
1432
- var eyesGroup = document.createElementNS(svgNS, 'g');
1433
- eyesGroup.setAttribute('clip-path', 'url(#' + clipId + ')');
1434
-
1435
- var eyeL = document.createElementNS(svgNS, 'rect');
1436
- eyeL.setAttribute('fill', '#ffffff');
1437
- var eyeR = document.createElementNS(svgNS, 'rect');
1438
- eyeR.setAttribute('fill', '#ffffff');
1439
- eyesGroup.appendChild(eyeL);
1440
- eyesGroup.appendChild(eyeR);
1441
- eyesLayer.appendChild(eyesGroup);
1442
-
1443
- return { bodyPath: bodyPath, eyesGroup: eyesGroup, eyeL: eyeL, eyeR: eyeR, defaultColor: defaultColor };
1444
- }
1445
-
1446
- var ghostLNode = createBotNode('obm-clip-ghostL-' + uid, '#8229cc');
1447
- var ghostRNode = createBotNode('obm-clip-ghostR-' + uid, '#47e4ad');
1448
- var centerNode = createBotNode('obm-clip-center-' + uid, CHARCOAL);
1449
-
1450
- var projector = new SvgProjector({ viewportSize: 280 });
1451
-
1452
- function colorToCss(c, def) {
1453
- if (!c) return def;
1454
- if (typeof c === 'number') return '#' + c.toString(16).padStart(6, '0');
1455
- return c;
1456
- }
1457
-
1458
- function applyPose(node, clipPathEl, pose) {
1459
- if (!node || !pose || pose.visible === false || (pose.scale !== undefined && pose.scale <= 0.001)) {
1460
- if (node && node.bodyPath) node.bodyPath.style.display = 'none';
1461
- if (node && node.eyesGroup) node.eyesGroup.style.display = 'none';
1462
- if (clipPathEl) clipPathEl.setAttribute('d', '');
1463
- return;
1464
- }
1465
- node.bodyPath.style.display = '';
1466
-
1467
- var res = projector.projectRoundedCube(pose);
1468
- if (!res.visible || !res.bodyPath) {
1469
- node.bodyPath.style.display = 'none';
1470
- node.eyesGroup.style.display = 'none';
1471
- if (clipPathEl) clipPathEl.setAttribute('d', '');
1472
- return;
1473
- }
1474
-
1475
- node.bodyPath.setAttribute('d', res.bodyPath);
1476
- if (clipPathEl) clipPathEl.setAttribute('d', res.bodyPath);
1477
-
1478
- var bodyFill = colorToCss(pose.bodyColor, node.defaultColor);
1479
- var eyeFill = colorToCss(pose.eyeColor, '#ffffff');
1480
- node.bodyPath.setAttribute('fill', bodyFill);
1481
-
1482
- if (res.eyes && res.eyes.length > 0) {
1483
- node.eyesGroup.style.display = '';
1484
- while (node.eyesGroup.children.length < res.eyes.length) {
1485
- node.eyesGroup.appendChild(document.createElementNS(svgNS, 'rect'));
1486
- }
1487
- while (node.eyesGroup.children.length > res.eyes.length) {
1488
- node.eyesGroup.removeChild(node.eyesGroup.lastChild);
1489
- }
1490
-
1491
- for (var i = 0; i < res.eyes.length; i++) {
1492
- var d = res.eyes[i];
1493
- var rectEl = node.eyesGroup.children[i];
1494
- rectEl.setAttribute('x', (-d.w / 2).toFixed(2));
1495
- rectEl.setAttribute('y', (-d.h / 2).toFixed(2));
1496
- rectEl.setAttribute('width', d.w.toFixed(2));
1497
- rectEl.setAttribute('height', d.h.toFixed(2));
1498
- rectEl.setAttribute('rx', d.rx.toFixed(2));
1499
- rectEl.setAttribute('ry', d.ry.toFixed(2));
1500
- rectEl.setAttribute('transform', 'translate(' + d.cx.toFixed(2) + ', ' + d.cy.toFixed(2) + ') rotate(' + d.angle.toFixed(2) + ')');
1501
- rectEl.setAttribute('opacity', (d.opacity !== undefined ? d.opacity : 1.0).toFixed(2));
1502
- rectEl.setAttribute('fill', colorToCss(d.color, eyeFill));
1503
- }
1504
- } else {
1505
- node.eyesGroup.style.display = 'none';
1506
- }
1507
- }
1508
-
1509
- function renderFrame(time) {
1510
- var st = window.poseFor ? window.poseFor(container.dataset.motion, window.previewTime ?? time) : getBotState(activeBotId, time);
1511
-
1512
- // Layer ordering
1513
- if (activeBotId === 7 && svg.lastElementChild !== dotsLayer) {
1514
- svg.appendChild(dotsLayer);
1515
- } else if (activeBotId !== 7 && svg.firstElementChild !== dotsLayer) {
1516
- svg.insertBefore(dotsLayer, botLayer);
1517
- }
1518
-
1519
- // Render dots layer
1520
- if (st && st.dots && st.dots.length > 0) {
1521
- dotsLayer.style.display = '';
1522
- while (dotsLayer.children.length < st.dots.length) {
1523
- dotsLayer.appendChild(document.createElementNS(svgNS, 'circle'));
1524
- }
1525
- while (dotsLayer.children.length > st.dots.length) {
1526
- dotsLayer.removeChild(dotsLayer.lastElementChild);
1527
- }
1528
- for (var di = 0; di < st.dots.length; di++) {
1529
- var dot = st.dots[di];
1530
- var cEl = dotsLayer.children[di];
1531
- if (!dot || !dot.visible || dot.r <= 0.1) {
1532
- cEl.style.display = 'none';
1533
- } else {
1534
- cEl.style.display = '';
1535
- cEl.setAttribute('cx', dot.x.toFixed(2));
1536
- cEl.setAttribute('cy', dot.y.toFixed(2));
1537
- cEl.setAttribute('r', dot.r.toFixed(2));
1538
- cEl.setAttribute('fill', CHARCOAL);
1539
- }
1540
- }
1541
- } else {
1542
- dotsLayer.style.display = 'none';
1543
- }
1544
-
1545
- // Render bot bodies
1546
- if (activeBotId === 6) {
1547
- applyPose(ghostLNode, clipPathGhostL, st.ghostL);
1548
- applyPose(ghostRNode, clipPathGhostR, st.ghostR);
1549
- applyPose(centerNode, clipPathCenter, st.botCenter);
1550
-
1551
- var maxSplit = Math.max(
1552
- st.splitL !== undefined ? st.splitL : (st.botCenter && st.botCenter.splitL) || 0,
1553
- st.splitR !== undefined ? st.splitR : (st.botCenter && st.botCenter.splitR) || 0
1554
- );
1555
- if (maxSplit > 0.08 && maxSplit < 0.92) {
1556
- bodiesLayer.setAttribute('filter', 'url(#obm-gooey-' + uid + ')');
1557
- } else {
1558
- bodiesLayer.removeAttribute('filter');
1559
- }
1560
- } else {
1561
- ghostLNode.bodyPath.style.display = 'none';
1562
- ghostLNode.eyesGroup.style.display = 'none';
1563
- ghostRNode.bodyPath.style.display = 'none';
1564
- ghostRNode.eyesGroup.style.display = 'none';
1565
- bodiesLayer.removeAttribute('filter');
1566
- if (centerNode && st && st.bot) {
1567
- applyPose(centerNode, clipPathCenter, st.bot);
1568
- }
1569
- }
1570
-
1571
- if (onFrame) {
1572
- onFrame(time, st.label, st);
1573
- }
1574
- }
1575
-
1576
- // Playback state
1577
- var currentTime = 0;
1578
- var isPlaying = autoplay;
1579
- var lastTimestamp = null;
1580
- var rafId = null;
1581
-
1582
- function tick(timestamp) {
1583
- if (!lastTimestamp) lastTimestamp = timestamp;
1584
- var dt = (timestamp - lastTimestamp) / 1000.0;
1585
- lastTimestamp = timestamp;
1586
-
1587
- if (isPlaying) {
1588
- currentTime += dt * speed;
1589
- if (loop) {
1590
- currentTime = ((currentTime % LOOP) + LOOP) % LOOP;
1591
- } else if (currentTime >= LOOP) {
1592
- currentTime = LOOP;
1593
- isPlaying = false;
1594
- }
1595
- }
1596
-
1597
- renderFrame(currentTime);
1598
-
1599
- if (isPlaying || loop) {
1600
- rafId = requestAnimationFrame(tick);
1601
- }
1602
- }
1603
-
1604
- renderFrame(0);
1605
- if (autoplay) {
1606
- rafId = requestAnimationFrame(tick);
1607
- }
1608
-
1609
- return {
1610
- play: function () {
1611
- if (!isPlaying) {
1612
- isPlaying = true;
1613
- lastTimestamp = null;
1614
- rafId = requestAnimationFrame(tick);
1615
- }
1616
- },
1617
- pause: function () {
1618
- isPlaying = false;
1619
- if (rafId) cancelAnimationFrame(rafId);
1620
- },
1621
- seek: function (t) {
1622
- currentTime = clamp(t, 0, LOOP);
1623
- renderFrame(currentTime);
1624
- },
1625
- setBot: function (idOrKey) {
1626
- activeBotId = resolveBotId(idOrKey);
1627
- renderFrame(currentTime);
1628
- },
1629
- setSpeed: function (s) {
1630
- speed = Math.max(0.01, s);
1631
- },
1632
- setSize: function (newSize) {
1633
- size = newSize;
1634
- svg.setAttribute('width', typeof size === 'number' ? (size + 'px') : size);
1635
- svg.setAttribute('height', typeof size === 'number' ? (size + 'px') : size);
1636
- },
1637
- getBotId: function () {
1638
- return activeBotId;
1639
- },
1640
- getTime: function () {
1641
- return currentTime;
1642
- },
1643
- isPlaying: function () {
1644
- return isPlaying;
1645
- },
1646
- destroy: function () {
1647
- if (rafId) cancelAnimationFrame(rafId);
1648
- container.innerHTML = '';
1649
- }
1650
- };
1651
- }
1652
-
1653
- return {
1654
- version: '1.0.0',
1655
- LOOP: LOOP,
1656
- BOTS: BOTS,
1657
- Easings: Easings,
1658
- PoseTimeline: PoseTimeline,
1659
- BlinkTrack: BlinkTrack,
1660
- DotGridRig: DotGridRig,
1661
- SvgProjector: SvgProjector,
1662
- resolveBotId: resolveBotId,
1663
- getBotState: getBotState,
1664
- getBot1State: getBot1State,
1665
- getBot2State: getBot2State,
1666
- getBot3State: getBot3State,
1667
- getBot4State: getBot4State,
1668
- getBot5State: getBot5State,
1669
- getBot6State: getBot6State,
1670
- getBot7State: getBot7State,
1671
- mount: mount
1672
- };
1673
- }));