agent-robot-avatar 0.3.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,875 +1,905 @@
1
- import AgentRobotAvatar, { registerAvatarExtension } from './agent-robot-avatar-extension-host.js';
2
-
3
- const proto = AgentRobotAvatar.prototype;
4
- const basePlay = proto.play;
5
- const baseNoteActivity = proto.noteActivity;
6
- const baseSleep = proto.sleep;
7
- const baseWake = proto.wake;
8
- const baseResetToIdle = proto._resetToIdle;
9
- const baseStartMorph = proto._startMorph;
10
- const baseAnimateHead = proto._animateHead;
11
- const baseUpdateBlink = proto._updateBlink;
12
- const baseUpdateLook = proto._updateLook;
13
- const baseUpdateHeadFollow = proto._updateHeadFollow;
14
- const baseUpdateDragJelly = proto._updateDragJelly;
15
- const baseOnPointerMove = proto._onPointerMove;
16
- const baseOnDragMove = proto._onDragMove;
17
- const baseOnDragStart = proto._onDragStart;
18
- const baseOnDragEnd = proto._onDragEnd;
19
- const baseResumeFrames = proto._resumeFrames;
20
- const baseCanPauseFrames = proto._canPauseFrames;
21
- const baseInput = proto.input;
22
- const baseStartWaiting = proto.startWaiting;
23
- const baseStopWaiting = proto.stopWaiting;
24
- const baseDraw = proto._draw;
25
-
26
- const DEFAULT_SIZE = 112;
27
- const ACTION_ALIASES = Object.freeze({
28
- idle: 'idle',
29
- bored: 'bored',
30
- waiting: 'waiting',
31
- wait: 'waiting',
32
- input: 'input',
33
- send: 'send',
34
- success: 'success',
35
- failure: 'failure',
36
- failed: 'failure',
37
- fail: 'failure',
38
- warning: 'warning',
39
- inspect: 'inspect',
40
- verify: 'inspect',
41
- review: 'inspect',
42
- angry: 'angry',
43
- blocked: 'blocked',
44
- 'policy-blocked': 'blocked',
45
- error: 'error',
46
- 'system-error': 'error',
47
- 'connection-error': 'error',
48
- surprise: 'surprise',
49
- sleep: 'sleep',
50
- wake: 'wake',
51
- });
52
-
53
- function normalizeAction(name) {
54
- const raw = String(name || '').trim().toLowerCase();
55
- const canonical = Object.hasOwn(ACTION_ALIASES, raw) ? ACTION_ALIASES[raw] : null;
56
- return { raw, canonical };
57
- }
58
-
59
- function wakePolicy(instance) {
60
- const value = String(instance.getAttribute('wake-on') || 'activity').trim().toLowerCase();
61
- return value === 'manual' || value === 'interaction' ? value : 'activity';
62
- }
63
-
64
- function requestedMotion(instance) {
65
- const value = String(instance.getAttribute('motion') || 'auto').trim().toLowerCase();
66
- return value === 'reduce' || value === 'full' ? value : 'auto';
67
- }
68
-
69
- function reducedMotion(instance) {
70
- const requested = requestedMotion(instance);
71
- if (requested === 'reduce') return true;
72
- if (requested === 'full') return false;
73
- // A fresh query preserves the existing WebKit runtime-preference hardening
74
- // without installing additional listeners.
75
- if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
76
- return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
77
- }
78
- return instance._runtimeMotionQuery?.matches === true;
79
- }
80
-
81
- function emitActionState(instance, record, phase, silent = false) {
82
- if (!record || (phase !== 'start' && record.terminal)) return;
83
- if (phase !== 'start') record.terminal = true;
84
- if (silent) return;
85
- instance.dispatchEvent(new CustomEvent('action-state', {
86
- detail: { action: record.action, phase, source: record.source },
87
- bubbles: true,
88
- composed: true,
89
- }));
90
- }
91
-
92
- function cancelActiveAction(instance, { silent = false } = {}) {
93
- const record = instance._activeActionState;
94
- if (!record || record.terminal) return;
95
- if (instance._activeActionState === record) instance._activeActionState = null;
96
- emitActionState(instance, record, 'cancel', silent);
97
- }
98
-
99
- function beginAction(instance, action, source, continuous = false) {
100
- clearAutoSleep(instance);
101
- cancelActiveAction(instance);
102
- const record = {
103
- id: (instance._actionStateSequence || 0) + 1,
104
- action,
105
- source,
106
- continuous,
107
- terminal: false,
108
- };
109
- instance._actionStateSequence = record.id;
110
- instance._activeActionState = record;
111
- emitActionState(instance, record, 'start');
112
- return record;
113
- }
114
-
115
- function finishAction(instance, record, phase = 'end') {
116
- if (!record || record.terminal) return;
117
- if (instance._activeActionState !== record) return;
118
- instance._activeActionState = null;
119
- emitActionState(instance, record, phase);
120
- scheduleAutoSleep(instance);
121
- }
122
-
123
- function trackFiniteAction(instance, record, result) {
124
- if (record.continuous) return;
125
- if (result && typeof result.then === 'function') {
126
- Promise.resolve(result).then(
127
- () => finishAction(instance, record, 'end'),
128
- () => finishAction(instance, record, 'cancel'),
129
- );
130
- } else {
131
- finishAction(instance, record, 'end');
132
- }
133
- }
134
-
135
- function parseSize(value) {
136
- const text = String(value ?? '').trim();
137
- const match = text.match(/^(?:\d+(?:\.\d+)?|\.\d+)(?:px)?$/i);
138
- if (!match) return DEFAULT_SIZE;
139
- const numeric = Number.parseFloat(text);
140
- if (!Number.isFinite(numeric) || numeric <= 0) return DEFAULT_SIZE;
141
- return numeric;
142
- }
143
-
144
- function applySize(instance) {
145
- if (!instance.hasAttribute('size')) {
146
- if (instance._runtimeSizeApplied) instance.style.removeProperty('--face-size');
147
- instance._runtimeSizeApplied = false;
148
- return;
149
- }
150
- const size = parseSize(instance.getAttribute('size'));
151
- instance.style.setProperty('--face-size', `${size}px`);
152
- instance._runtimeSizeApplied = true;
153
- }
154
-
155
- function hasVisibleLayout(instance) {
156
- if (!instance.isConnected) return false;
157
- const rects = instance.getClientRects?.();
158
- if (!rects || rects.length === 0) return false;
159
- const rect = instance.getBoundingClientRect();
160
- return rect.width > 0 && rect.height > 0;
161
- }
162
-
163
- function cancelHeadAnimations(instance) {
164
- const animations = instance._headMotion?.getAnimations?.() || [];
165
- for (const animation of animations) animation.cancel();
166
- if (instance._headMotion) instance._headMotion.style.transform = '';
167
- }
168
-
169
-
170
- function cancelContinuousMotion(instance) {
171
- cancelHeadAnimations(instance);
172
- instance._blinkAnim = null;
173
- instance._blink = 1;
174
- instance._boredRoutine = null;
175
- instance._boredLookSpeed = null;
176
- if (instance._wanderTarget) instance._wanderTarget.x = instance._wanderTarget.y = 0;
177
- if (instance._wander) instance._wander.x = instance._wander.y = 0;
178
- if (instance._look) instance._look.x = instance._look.y = 0;
179
- }
180
-
181
- function dragAtRest(drag) {
182
- if (!drag || drag.active || drag.returning || drag.pendingReaction) return false;
183
- return Math.abs(drag.x) < 0.0001 && Math.abs(drag.y) < 0.0001 &&
184
- Math.abs(drag.vx) < 0.0001 && Math.abs(drag.vy) < 0.0001 &&
185
- Math.abs(drag.stretch) < 0.0001 && Math.abs(drag.shear) < 0.0001 &&
186
- Math.abs(drag.pullX) < 0.0001 && Math.abs(drag.pullY) < 0.0001;
187
- }
188
-
189
- function clearIdleDragVisuals(instance) {
190
- if (!dragAtRest(instance._dragJelly)) return;
191
- if (instance._dragMotion) {
192
- instance._dragMotion.style.transform = '';
193
- instance._dragMotion.style.transformOrigin = '';
194
- }
195
- if (instance._headShape && instance._baseHeadPathD) {
196
- instance._headShape.setAttribute('d', instance._baseHeadPathD);
197
- }
198
- }
199
-
200
- function clearAutoSleep(instance) {
201
- if (!instance._runtimeAutoSleepTimer) return;
202
- clearTimeout(instance._runtimeAutoSleepTimer);
203
- instance._runtimeAutoSleepTimer = 0;
204
- }
205
-
206
- function autoSleepBlocked(instance) {
207
- const record = instance._activeActionState;
208
- return Boolean(
209
- !instance.isConnected ||
210
- instance._runtimeDisconnecting ||
211
- instance._sleeping ||
212
- (record && !record.terminal && record.source !== 'interaction') ||
213
- instance._waitingRequested ||
214
- instance._waitingFx ||
215
- instance._inputWanted ||
216
- instance._state === 'input' ||
217
- instance._expressionLock
218
- );
219
- }
220
-
221
- function scheduleAutoSleep(instance) {
222
- clearAutoSleep(instance);
223
- const delayMs = Number(instance._autoSleepMs);
224
- if (!Number.isFinite(delayMs) || delayMs <= 0 || autoSleepBlocked(instance)) return;
225
- const remaining = Math.max(0, (instance._lastActivity + delayMs) - performance.now());
226
- instance._runtimeAutoSleepTimer = setTimeout(() => {
227
- instance._runtimeAutoSleepTimer = 0;
228
- if (autoSleepBlocked(instance)) return;
229
- const currentDelay = Number(instance._autoSleepMs);
230
- if (!Number.isFinite(currentDelay) || currentDelay <= 0) return;
231
- const nextRemaining = (instance._lastActivity + currentDelay) - performance.now();
232
- if (nextRemaining > 1) {
233
- scheduleAutoSleep(instance);
234
- return;
235
- }
236
- const previousSource = instance._runtimeActionSource;
237
- instance._runtimeActionSource = 'automatic';
238
- try {
239
- instance.sleep();
240
- } finally {
241
- instance._runtimeActionSource = previousSource;
242
- }
243
- }, remaining);
244
- }
245
-
246
- function requestVisualCommit(instance) {
247
- if (!instance.isConnected || instance._runtimeDisconnecting) return;
248
- instance._runtimeVisualDirty = true;
249
- instance._resumeFrames?.();
250
- }
251
-
252
- function syncMotionPreference(instance) {
253
- const reduced = reducedMotion(instance);
254
- if (instance._runtimeLastReducedMotion === reduced) return reduced;
255
- instance._runtimeLastReducedMotion = reduced;
256
- instance._runtimeVisualDirty = true;
257
- if (reduced) cancelContinuousMotion(instance);
258
- return reduced;
259
- }
260
-
261
- function clearDragGeometry(instance, { preserveClick = false, releaseCapture = true } = {}) {
262
- const drag = instance._dragJelly;
263
- if (!drag) return;
264
- const pointerId = drag.pointerId;
265
- const suppressClick = preserveClick && drag.moved;
266
-
267
- drag.active = false;
268
- drag.returning = false;
269
- drag.snapped = false;
270
- drag.pointerId = null;
271
- drag.pendingReaction = null;
272
- drag.targetX = drag.targetY = drag.x = drag.y = drag.vx = drag.vy = 0;
273
- drag.targetStretch = drag.stretch = drag.stretchVel = 0;
274
- drag.targetShear = drag.shear = drag.shearVel = 0;
275
- drag.targetPullX = drag.targetPullY = drag.pullX = drag.pullY = drag.pullVX = drag.pullVY = 0;
276
- drag.angle = 0;
277
- drag.maxDist = 0;
278
- drag.ux = drag.uy = 0;
279
- drag.anchorX = drag.anchorY = 50;
280
- instance._pendingDragEvent = null;
281
-
282
- if (releaseCapture && pointerId != null) {
283
- try { instance.releasePointerCapture(pointerId); } catch (_) {}
284
- }
285
- if (instance._dragMotion) {
286
- instance._dragMotion.style.transform = '';
287
- instance._dragMotion.style.transformOrigin = '';
288
- }
289
- if (instance._headShape && instance._baseHeadPathD) {
290
- instance._headShape.setAttribute('d', instance._baseHeadPathD);
291
- }
292
- instance._suppressClick = suppressClick;
293
- }
294
-
295
- function programActionOwnsExpression(instance) {
296
- const record = instance._activeActionState;
297
- if (record && !record.terminal && record.source !== 'interaction') return true;
298
- return Boolean(
299
- instance._waitingRequested ||
300
- instance._waitingFx ||
301
- instance._inputWanted ||
302
- instance._inspectFx ||
303
- instance._failureFx ||
304
- instance._warningFx ||
305
- instance._systemErrorShake ||
306
- instance._sleeping ||
307
- (instance._expressionLock && instance._state !== 'idle')
308
- );
309
- }
310
-
311
- function startDragReaction(instance, reaction) {
312
- if (!reaction || programActionOwnsExpression(instance)) return;
313
- const result = reaction === 'angry'
314
- ? instance.angry({ fromDrag: true })
315
- : instance.success({ fromDrag: true });
316
- const record = beginAction(instance, 'reaction', 'interaction', false);
317
- trackFiniteAction(instance, record, result);
318
- }
319
-
320
- function finishDragReturn(instance, reaction) {
321
- clearDragGeometry(instance, { preserveClick: true, releaseCapture: false });
322
- startDragReaction(instance, reaction);
323
- }
324
-
325
- function applyDragTransform(instance) {
326
- const drag = instance._dragJelly;
327
- if (!drag) return;
328
- instance._applyHeadDeform?.();
329
- if (!instance._dragMotion) return;
330
- const sx = 1 + drag.stretch;
331
- const sy = 1 - drag.stretch * 0.30;
332
- const shearDeg = drag.shear * 180 / Math.PI;
333
- instance._dragMotion.style.transformOrigin = `${drag.anchorX.toFixed(2)}% ${drag.anchorY.toFixed(2)}%`;
334
- instance._dragMotion.style.transform = `translate(${drag.x.toFixed(2)}px, ${drag.y.toFixed(2)}px) rotate(${drag.angle.toFixed(4)}rad) scale(${sx.toFixed(4)}, ${sy.toFixed(4)}) skewY(${shearDeg.toFixed(3)}deg) rotate(${(-drag.angle).toFixed(4)}rad)`;
335
- }
336
-
337
- function flushPointerWork(instance) {
338
- const pointer = instance._pendingPointerEvent;
339
- instance._pendingPointerEvent = null;
340
- if (pointer) {
341
- baseOnPointerMove.call(instance, pointer);
342
- instance._runtimePointerFlushCount = (instance._runtimePointerFlushCount || 0) + 1;
343
- }
344
-
345
- const drag = instance._pendingDragEvent;
346
- instance._pendingDragEvent = null;
347
- if (drag && instance._dragJelly?.active && drag.pointerId === instance._dragJelly.pointerId) {
348
- baseOnDragMove.call(instance, drag);
349
- instance._runtimeDragFlushCount = (instance._runtimeDragFlushCount || 0) + 1;
350
- }
351
- }
352
-
353
- function setRuntimeVisible(instance, visible) {
354
- const next = visible === true;
355
- if (instance._runtimeVisible === next) return;
356
- instance._runtimeVisible = next;
357
- if (!next) {
358
- if (instance._raf) cancelAnimationFrame(instance._raf);
359
- instance._raf = 0;
360
- instance._framePaused = true;
361
- instance._pendingPointerEvent = null;
362
- if (instance._dragJelly?.active || instance._dragJelly?.returning) {
363
- clearDragGeometry(instance, { preserveClick: true });
364
- }
365
- cancelHeadAnimations(instance);
366
- if (instance._antennaSpring) {
367
- instance._antennaSpring.vx = 0;
368
- instance._antennaSpring.vy = 0;
369
- instance._antennaSpring.initialized = false;
370
- }
371
- return;
372
- }
373
- instance._resumeFrames?.();
374
- }
375
-
376
- function handleMotionChange(instance) {
377
- const reduced = syncMotionPreference(instance);
378
- if (reduced) {
379
- cancelContinuousMotion(instance);
380
- instance._pose = { ...instance._toPose };
381
- instance._fromPose = { ...instance._toPose };
382
- instance._morphDuration = 0;
383
- if (instance._dragJelly?.returning) finishDragReturn(instance, instance._dragJelly.pendingReaction);
384
- }
385
- requestVisualCommit(instance);
386
- scheduleAutoSleep(instance);
387
- }
388
-
389
- function ensureRuntime(instance) {
390
- if (instance._runtimePolicyReady || !instance.isConnected || instance._runtimeDisconnecting) return;
391
- instance._runtimePolicyReady = true;
392
- if (!instance.style.touchAction) instance.style.touchAction = 'pinch-zoom';
393
- applySize(instance);
394
-
395
- if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
396
- const query = window.matchMedia('(prefers-reduced-motion: reduce)');
397
- const listener = () => handleMotionChange(instance);
398
- instance._runtimeMotionQuery = query;
399
- instance._runtimeMotionListener = listener;
400
- if (query.addEventListener) query.addEventListener('change', listener);
401
- else query.addListener?.(listener);
402
- }
403
-
404
- if (typeof MutationObserver !== 'undefined') {
405
- instance._runtimeAttributeObserver = new MutationObserver(records => {
406
- let motionChanged = false;
407
- let autoSleepChanged = false;
408
- for (const record of records) {
409
- if (record.attributeName === 'size') applySize(instance);
410
- if (record.attributeName === 'motion') motionChanged = true;
411
- if (record.attributeName === 'auto-sleep') autoSleepChanged = true;
412
- }
413
- if (motionChanged) handleMotionChange(instance);
414
- if (autoSleepChanged) scheduleAutoSleep(instance);
415
- });
416
- instance._runtimeAttributeObserver.observe(instance, {
417
- attributes: true,
418
- attributeFilter: ['size', 'motion', 'wake-on', 'auto-sleep'],
419
- });
420
- }
421
-
422
- if (typeof IntersectionObserver !== 'undefined') {
423
- instance._runtimeIntersectionObserver = new IntersectionObserver(entries => {
424
- const entry = entries[entries.length - 1];
425
- if (!entry) return;
426
- instance._runtimeIntersecting = entry.isIntersecting;
427
- setRuntimeVisible(instance, entry.isIntersecting && hasVisibleLayout(instance));
428
- });
429
- instance._runtimeIntersectionObserver.observe(instance);
430
- }
431
-
432
- if (typeof ResizeObserver !== 'undefined') {
433
- instance._runtimeResizeObserver = new ResizeObserver(() => {
434
- const inView = instance._runtimeIntersecting !== false;
435
- setRuntimeVisible(instance, inView && hasVisibleLayout(instance));
436
- });
437
- instance._runtimeResizeObserver.observe(instance);
438
- }
439
-
440
- instance._runtimeVisible = hasVisibleLayout(instance);
441
- instance._runtimeLostCapture = event => {
442
- if (instance._dragJelly?.active && event.pointerId === instance._dragJelly.pointerId) {
443
- clearDragGeometry(instance, { preserveClick: false, releaseCapture: false });
444
- }
445
- };
446
- instance.addEventListener('lostpointercapture', instance._runtimeLostCapture);
447
-
448
- if (!instance._runtimeLoopWrapped && typeof instance._loop === 'function') {
449
- const loop = instance._loop;
450
- instance._loop = ts => {
451
- flushPointerWork(instance);
452
- return loop(ts);
453
- };
454
- instance._runtimeLoopWrapped = true;
455
- }
456
- scheduleAutoSleep(instance);
457
- }
458
-
459
- function teardownRuntime(instance) {
460
- clearAutoSleep(instance);
461
- cancelContinuousMotion(instance);
462
- instance._runtimeIntersectionObserver?.disconnect();
463
- instance._runtimeResizeObserver?.disconnect();
464
- instance._runtimeAttributeObserver?.disconnect();
465
- if (instance._runtimeMotionQuery && instance._runtimeMotionListener) {
466
- if (instance._runtimeMotionQuery.removeEventListener) {
467
- instance._runtimeMotionQuery.removeEventListener('change', instance._runtimeMotionListener);
468
- } else {
469
- instance._runtimeMotionQuery.removeListener?.(instance._runtimeMotionListener);
470
- }
471
- }
472
- if (instance._runtimeLostCapture) {
473
- instance.removeEventListener('lostpointercapture', instance._runtimeLostCapture);
474
- }
475
- instance._runtimeIntersectionObserver = null;
476
- instance._runtimeResizeObserver = null;
477
- instance._runtimeAttributeObserver = null;
478
- instance._runtimeMotionQuery = null;
479
- instance._runtimeMotionListener = null;
480
- instance._runtimeLostCapture = null;
481
- instance._runtimePolicyReady = false;
482
- instance._runtimeVisible = false;
483
- instance._runtimeLastReducedMotion = undefined;
484
- instance._runtimeVisualDirty = false;
485
- instance._pendingPointerEvent = null;
486
- instance._pendingDragEvent = null;
487
- }
488
-
489
- function eventTargetsAvatar(event, instance) {
490
- const path = event?.composedPath?.();
491
- if (Array.isArray(path)) return path.includes(instance);
492
- return event?.target === instance || instance.contains?.(event?.target);
493
- }
494
-
495
- proto._isReducedMotion = function() {
496
- return reducedMotion(this);
497
- };
498
-
499
- proto.noteActivity = function(wake = true) {
500
- ensureRuntime(this);
501
- const shouldWake = wake !== false && (this._sleeping || this._state === 'sleep');
502
- const result = baseNoteActivity.call(this, false);
503
- scheduleAutoSleep(this);
504
- if (shouldWake) this.wake();
505
- return result;
506
- };
507
-
508
- proto._noteEnvironmentActivity = function(event) {
509
- ensureRuntime(this);
510
- const shouldConsiderWake = this._sleeping || this._state === 'sleep';
511
- const result = baseNoteActivity.call(this, false);
512
- scheduleAutoSleep(this);
513
- if (!shouldConsiderWake) return result;
514
-
515
- const policy = wakePolicy(this);
516
- const shouldWake = policy === 'activity' || (policy === 'interaction' && eventTargetsAvatar(event, this));
517
- if (!shouldWake) return result;
518
-
519
- const previousSource = this._runtimeActionSource;
520
- this._runtimeActionSource = 'automatic';
521
- try {
522
- return this.wake();
523
- } finally {
524
- this._runtimeActionSource = previousSource;
525
- }
526
- };
527
-
528
- proto._resetToIdle = function(notify = true) {
529
- const previous = this._runtimeResetNotify;
530
- this._runtimeResetNotify = notify;
531
- try {
532
- return baseResetToIdle.call(this, notify);
533
- } finally {
534
- this._runtimeResetNotify = previous;
535
- scheduleAutoSleep(this);
536
- }
537
- };
538
-
539
- proto._startMorph = function(target, duration, ease) {
540
- const reduced = reducedMotion(this);
541
- const result = baseStartMorph.call(this, target, reduced ? 0 : duration, ease);
542
- if (reduced) requestVisualCommit(this);
543
- return result;
544
- };
545
-
546
- proto._animateHead = function(frames, duration) {
547
- if (reducedMotion(this)) {
548
- cancelHeadAnimations(this);
549
- return undefined;
550
- }
551
- return baseAnimateHead.call(this, frames, duration);
552
- };
553
-
554
- proto._updateBlink = function(now) {
555
- if (!reducedMotion(this)) return baseUpdateBlink.call(this, now);
556
- this._blinkAnim = null;
557
- this._blink = 1;
558
- };
559
-
560
- proto._updateLook = function(now, dt) {
561
- if (!reducedMotion(this)) return baseUpdateLook.call(this, now, dt);
562
- this._boredRoutine = null;
563
- this._boredLookSpeed = null;
564
- this._wanderTarget.x = this._wanderTarget.y = 0;
565
- this._wander.x = this._wander.y = 0;
566
- this._look.x = this._look.y = 0;
567
- };
568
-
569
- proto._updateHeadFollow = function(now, dt) {
570
- if (!reducedMotion(this)) return baseUpdateHeadFollow.call(this, now, dt);
571
- this._headFollowPose.x = this._headFollowPose.y = this._headFollowPose.rot = 0;
572
- this._headFollowVel.x = this._headFollowVel.y = this._headFollowVel.rot = 0;
573
- if (this._headFollow) this._headFollow.setAttribute('transform', '');
574
- };
575
-
576
- proto._updateDragJelly = function(dt) {
577
- const drag = this._dragJelly;
578
- if (!reducedMotion(this)) {
579
- const result = baseUpdateDragJelly.call(this, dt);
580
- clearIdleDragVisuals(this);
581
- return result;
582
- }
583
- if (!drag) return;
584
- if (drag.active) {
585
- drag.x = drag.targetX;
586
- drag.y = drag.targetY;
587
- drag.stretch = drag.targetStretch;
588
- drag.shear = drag.targetShear;
589
- drag.pullX = drag.targetPullX;
590
- drag.pullY = drag.targetPullY;
591
- applyDragTransform(this);
592
- } else if (drag.returning) {
593
- finishDragReturn(this, drag.pendingReaction);
594
- }
595
- clearIdleDragVisuals(this);
596
- };
597
-
598
- proto._onPointerMove = function(event) {
599
- ensureRuntime(this);
600
- if (this._runtimeVisible === false) return;
601
- this._pendingPointerEvent = {
602
- clientX: event.clientX,
603
- clientY: event.clientY,
604
- };
605
- this._resumeFrames?.();
606
- };
607
-
608
- proto._onDragMove = function(event) {
609
- ensureRuntime(this);
610
- if (!this._dragJelly?.active || event.pointerId !== this._dragJelly.pointerId) return;
611
- this._pendingDragEvent = {
612
- clientX: event.clientX,
613
- clientY: event.clientY,
614
- pointerId: event.pointerId,
615
- };
616
- this._resumeFrames?.();
617
- };
618
-
619
- proto._onDragStart = function(event) {
620
- ensureRuntime(this);
621
- if (this._dragJelly?.active) return;
622
- if (event.pointerType === 'touch' && event.isPrimary === false) return;
623
- return baseOnDragStart.call(this, event);
624
- };
625
-
626
- proto._onDragEnd = function(event) {
627
- const drag = this._dragJelly;
628
- if (!drag?.active || event.pointerId !== drag.pointerId) return;
629
- flushPointerWork(this);
630
- if (event.type === 'pointercancel') {
631
- clearDragGeometry(this, { preserveClick: false });
632
- return;
633
- }
634
- baseOnDragEnd.call(this, event);
635
- if (reducedMotion(this) && drag.returning) finishDragReturn(this, drag.pendingReaction);
636
- };
637
-
638
- proto._finishDragReturn = function(reaction) {
639
- finishDragReturn(this, reaction);
640
- };
641
-
642
- proto._resumeFrames = function() {
643
- if (!this.isConnected || this._runtimeDisconnecting) return;
644
- ensureRuntime(this);
645
- if (this._runtimeVisible === false) return;
646
- if (syncMotionPreference(this)) this._runtimeVisualDirty = true;
647
- return baseResumeFrames.call(this);
648
- };
649
-
650
- proto._draw = function(now) {
651
- syncMotionPreference(this);
652
- const result = baseDraw.call(this, now);
653
- this._runtimeVisualDirty = false;
654
- return result;
655
- };
656
-
657
- proto._canPauseFrames = function(now) {
658
- if (this._runtimeVisible === false) return true;
659
- const reduced = syncMotionPreference(this);
660
- if (!reduced) return baseCanPauseFrames.call(this, now);
661
- if (this._pendingPointerEvent || this._pendingDragEvent || this._runtimeVisualDirty) return false;
662
- return true;
663
- };
664
-
665
- function playNoOp(instance, canonical) {
666
- if (canonical === 'wake') return !instance._sleeping && instance._state !== 'sleep';
667
- if (canonical === 'sleep') return instance._sleeping === true;
668
- if (canonical === 'input') return instance._inputWanted || instance._state === 'input';
669
- return false;
670
- }
671
-
672
- function leaveSleepForAction(instance) {
673
- if (!instance._sleeping && instance._state !== 'sleep') return;
674
- instance._sleeping = false;
675
- instance.setState('idle', { duration: reducedMotion(instance) ? 0 : 120 });
676
- }
677
-
678
- function prepareReplacement(instance, canonical) {
679
- clearAutoSleep(instance);
680
- cancelActiveAction(instance);
681
- clearDragGeometry(instance, { preserveClick: true });
682
- instance._cancelPendingWaits?.();
683
- if (canonical !== 'sleep' && canonical !== 'wake' && canonical !== 'idle') {
684
- leaveSleepForAction(instance);
685
- }
686
- }
687
-
688
- proto.play = function(name) {
689
- ensureRuntime(this);
690
- const { raw, canonical } = normalizeAction(name);
691
- if (!canonical) throw new Error(`Unknown Agent Robot Avatar action: ${name}`);
692
- if (playNoOp(this, canonical)) return this;
693
- if (canonical === 'idle') return basePlay.call(this, raw);
694
-
695
- prepareReplacement(this, canonical);
696
-
697
- let result;
698
- this._runtimeInPlay = true;
699
- try {
700
- result = basePlay.call(this, raw);
701
- } finally {
702
- this._runtimeInPlay = false;
703
- }
704
-
705
- const record = beginAction(this, canonical, 'api', canonical === 'input');
706
- trackFiniteAction(this, record, result);
707
- if (reducedMotion(this)) queueMicrotask(() => cancelHeadAnimations(this));
708
- return result;
709
- };
710
-
711
- proto.input = function(active = true) {
712
- if (this._runtimeInPlay) return baseInput.call(this, active);
713
- ensureRuntime(this);
714
- if (active) {
715
- if (this._inputWanted || this._state === 'input') return this;
716
- prepareReplacement(this, 'input');
717
- const result = baseInput.call(this, true);
718
- beginAction(this, 'input', 'api', true);
719
- return result;
720
- }
721
-
722
- const record = this._activeActionState?.action === 'input' ? this._activeActionState : null;
723
- const result = baseInput.call(this, false);
724
- if (record) finishAction(this, record, 'end');
725
- return result;
726
- };
727
-
728
- proto.startWaiting = async function() {
729
- ensureRuntime(this);
730
- clearAutoSleep(this);
731
- const result = await baseStartWaiting.call(this);
732
- if (this._waitingRequested && this._waitingFx) beginAction(this, 'waiting', 'api', true);
733
- return result;
734
- };
735
-
736
- proto.stopWaiting = function() {
737
- ensureRuntime(this);
738
- const record = this._activeActionState?.action === 'waiting' ? this._activeActionState : null;
739
- this._runtimeEndingWaiting = Boolean(record);
740
- let result;
741
- try {
742
- result = baseStopWaiting.call(this);
743
- } finally {
744
- this._runtimeEndingWaiting = false;
745
- }
746
- if (record) finishAction(this, record, 'end');
747
- return result;
748
- };
749
-
750
- proto.sleep = function() {
751
- if (this._runtimeInPlay) return baseSleep.call(this);
752
- ensureRuntime(this);
753
- if (this._sleeping) return this;
754
- prepareReplacement(this, 'sleep');
755
- const source = this._runtimeActionSource || 'api';
756
- const result = baseSleep.call(this);
757
- const record = beginAction(this, 'sleep', source, false);
758
- trackFiniteAction(this, record, result);
759
- return result;
760
- };
761
-
762
- proto.wake = function() {
763
- if (this._runtimeInPlay) return baseWake.call(this);
764
- ensureRuntime(this);
765
- if (!this._sleeping && this._state !== 'sleep') return this;
766
- prepareReplacement(this, 'wake');
767
- const source = this._runtimeActionSource || 'api';
768
- const result = baseWake.call(this);
769
- const record = beginAction(this, 'wake', source, false);
770
- trackFiniteAction(this, record, result);
771
- return result;
772
- };
773
-
774
- proto._autoSleep = function() {
775
- // Auto-sleep is scheduled independently from drawing by scheduleAutoSleep().
776
- };
777
-
778
- proto._scheduleAutoSleep = function() {
779
- scheduleAutoSleep(this);
780
- };
781
-
782
- proto._teardownRuntime = function() {
783
- teardownRuntime(this);
784
- };
785
-
786
- function setMask(top, bottom, topY, bottomY, topAngle = 0, bottomAngle = 0) {
787
- if (top) {
788
- top.setAttribute('y', (topY - 90).toFixed(2));
789
- top.setAttribute('height', '90');
790
- top.setAttribute('transform', `rotate(${topAngle.toFixed(2)} 0 ${topY.toFixed(2)})`);
791
- }
792
- if (bottom) {
793
- bottom.setAttribute('y', bottomY.toFixed(2));
794
- bottom.setAttribute('height', '90');
795
- bottom.setAttribute('transform', `rotate(${bottomAngle.toFixed(2)} 0 ${bottomY.toFixed(2)})`);
796
- }
797
- }
798
-
799
- function setEye(eye, x, y = 126, sx = 1, sy = 1) {
800
- if (eye) eye.setAttribute('transform', `translate(${x.toFixed(2)} ${y.toFixed(2)}) scale(${sx.toFixed(3)} ${sy.toFixed(3)})`);
801
- }
802
-
803
- function drawReducedState(instance) {
804
- if (!reducedMotion(instance)) return;
805
- if (instance._state === 'input') {
806
- instance._leftInputBase?.setAttribute('opacity', '1');
807
- instance._rightInputBase?.setAttribute('opacity', '1');
808
- }
809
- if (instance._antennaDot) instance._antennaDot.style.opacity = '1';
810
-
811
- if (instance._waitingFx) {
812
- setEye(instance._leftEye, 100, 126, 0.92, 1);
813
- setEye(instance._rightEye, 140, 126, 0.92, 1);
814
- return;
815
- }
816
- if (instance._inspectFx) {
817
- setEye(instance._leftEye, 86);
818
- setEye(instance._rightEye, 154);
819
- setMask(instance._leftTop, instance._leftBottom, -8, 8);
820
- setMask(instance._rightTop, instance._rightBottom, -8, 8);
821
- return;
822
- }
823
- if (instance._warningFx) {
824
- setEye(instance._leftEye, 100, 126, 1.16, 1.10);
825
- setEye(instance._rightEye, 172, 132, 0.84, 0.96);
826
- setMask(instance._leftTop, instance._leftBottom, -18, 35, 8, 0);
827
- setMask(instance._rightTop, instance._rightBottom, -20, 36, -7, 0);
828
- return;
829
- }
830
- if (instance._systemErrorShake) {
831
- setMask(instance._leftTop, instance._leftBottom, -5, 36, -15, 0);
832
- setMask(instance._rightTop, instance._rightBottom, -5, 36, 15, 0);
833
- }
834
- }
835
-
836
- for (const property of ['_waitingFx', '_inspectFx', '_failureFx', '_warningFx', '_systemErrorShake']) {
837
- const slot = Symbol(property);
838
- Object.defineProperty(proto, property, {
839
- configurable: true,
840
- get() { return this[slot]; },
841
- set(value) {
842
- this[slot] = value;
843
- this._runtimeVisualDirty = true;
844
- if (this.isConnected && !this._runtimeDisconnecting && syncMotionPreference(this)) {
845
- requestVisualCommit(this);
846
- queueMicrotask(() => {
847
- if (this.isConnected && !this._runtimeDisconnecting && syncMotionPreference(this)) {
848
- cancelContinuousMotion(this);
849
- }
850
- });
851
- }
852
- },
853
- });
854
- }
855
-
856
- registerAvatarExtension({
857
- name: 'runtime-policy',
858
- reset() {
859
- const silent = this._runtimeResetNotify === false;
860
- if (!this._runtimeEndingWaiting) cancelActiveAction(this, { silent });
861
- clearDragGeometry(this, { preserveClick: !silent });
862
- this._pendingPointerEvent = null;
863
- },
864
- draw() {
865
- ensureRuntime(this);
866
- drawReducedState(this);
867
- },
868
- });
869
-
870
- export {
871
- AgentRobotAvatar,
872
- ACTION_ALIASES,
873
- DEFAULT_SIZE,
874
- };
875
- export default AgentRobotAvatar;
1
+ import AgentRobotAvatar, { registerAvatarExtension } from './agent-robot-avatar-extension-host.js';
2
+
3
+ const proto = AgentRobotAvatar.prototype;
4
+ const basePlay = proto.play;
5
+ const baseNoteActivity = proto.noteActivity;
6
+ const baseSleep = proto.sleep;
7
+ const baseWake = proto.wake;
8
+ const baseResetToIdle = proto._resetToIdle;
9
+ const baseStartMorph = proto._startMorph;
10
+ const baseAnimateHead = proto._animateHead;
11
+ const baseUpdateBlink = proto._updateBlink;
12
+ const baseUpdateLook = proto._updateLook;
13
+ const baseUpdateHeadFollow = proto._updateHeadFollow;
14
+ const baseUpdateDragJelly = proto._updateDragJelly;
15
+ const baseOnPointerMove = proto._onPointerMove;
16
+ const baseOnDragMove = proto._onDragMove;
17
+ const baseOnDragStart = proto._onDragStart;
18
+ const baseOnDragEnd = proto._onDragEnd;
19
+ const baseResumeFrames = proto._resumeFrames;
20
+ const baseCanPauseFrames = proto._canPauseFrames;
21
+ const baseInput = proto.input;
22
+ const baseStartWaiting = proto.startWaiting;
23
+ const baseStopWaiting = proto.stopWaiting;
24
+ const baseDraw = proto._draw;
25
+
26
+ const DEFAULT_SIZE = 112;
27
+ const ACTION_ALIASES = Object.freeze({
28
+ idle: 'idle',
29
+ bored: 'bored',
30
+ waiting: 'waiting',
31
+ wait: 'waiting',
32
+ 'waiting-wrap': 'waiting',
33
+ input: 'input',
34
+ send: 'send',
35
+ success: 'success',
36
+ failure: 'failure',
37
+ failed: 'failure',
38
+ fail: 'failure',
39
+ warning: 'warning',
40
+ inspect: 'inspect',
41
+ verify: 'inspect',
42
+ review: 'inspect',
43
+ angry: 'angry',
44
+ blocked: 'blocked',
45
+ 'policy-blocked': 'blocked',
46
+ error: 'error',
47
+ 'system-error': 'error',
48
+ 'connection-error': 'error',
49
+ surprise: 'surprise',
50
+ love: 'love',
51
+ random: 'random',
52
+ slot: 'random',
53
+ sleep: 'sleep',
54
+ wake: 'wake',
55
+ });
56
+
57
+ function normalizeAction(name) {
58
+ const raw = String(name || '').trim().toLowerCase();
59
+ const canonical = Object.hasOwn(ACTION_ALIASES, raw) ? ACTION_ALIASES[raw] : null;
60
+ return { raw, canonical };
61
+ }
62
+
63
+ function wakePolicy(instance) {
64
+ const value = String(instance.getAttribute('wake-on') || 'activity').trim().toLowerCase();
65
+ return value === 'manual' || value === 'interaction' ? value : 'activity';
66
+ }
67
+
68
+ function requestedMotion(instance) {
69
+ const value = String(instance.getAttribute('motion') || 'auto').trim().toLowerCase();
70
+ return value === 'reduce' || value === 'full' ? value : 'auto';
71
+ }
72
+
73
+ function reducedMotion(instance) {
74
+ const requested = requestedMotion(instance);
75
+ if (requested === 'reduce') return true;
76
+ if (requested === 'full') return false;
77
+ // A fresh query preserves the existing WebKit runtime-preference hardening
78
+ // without installing additional listeners.
79
+ if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
80
+ return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
81
+ }
82
+ return instance._runtimeMotionQuery?.matches === true;
83
+ }
84
+
85
+ function emitActionState(instance, record, phase, silent = false) {
86
+ if (!record || (phase !== 'start' && record.terminal)) return;
87
+ if (phase !== 'start') record.terminal = true;
88
+ if (silent) return;
89
+ instance.dispatchEvent(new CustomEvent('action-state', {
90
+ detail: { action: record.action, phase, source: record.source },
91
+ bubbles: true,
92
+ composed: true,
93
+ }));
94
+ }
95
+
96
+ function cancelActiveAction(instance, { silent = false } = {}) {
97
+ const record = instance._activeActionState;
98
+ if (!record || record.terminal) return;
99
+ if (instance._activeActionState === record) instance._activeActionState = null;
100
+ emitActionState(instance, record, 'cancel', silent);
101
+ }
102
+
103
+ function beginAction(instance, action, source, continuous = false) {
104
+ clearAutoSleep(instance);
105
+ cancelActiveAction(instance);
106
+ const record = {
107
+ id: (instance._actionStateSequence || 0) + 1,
108
+ action,
109
+ source,
110
+ continuous,
111
+ terminal: false,
112
+ };
113
+ instance._actionStateSequence = record.id;
114
+ instance._activeActionState = record;
115
+ emitActionState(instance, record, 'start');
116
+ return record;
117
+ }
118
+
119
+ function finishAction(instance, record, phase = 'end') {
120
+ if (!record || record.terminal) return;
121
+ if (instance._activeActionState !== record) return;
122
+ instance._activeActionState = null;
123
+ emitActionState(instance, record, phase);
124
+ scheduleAutoSleep(instance);
125
+ }
126
+
127
+ function trackFiniteAction(instance, record, result) {
128
+ if (record.continuous) return;
129
+ if (result && typeof result.then === 'function') {
130
+ Promise.resolve(result).then(
131
+ () => finishAction(instance, record, 'end'),
132
+ () => finishAction(instance, record, 'cancel'),
133
+ );
134
+ } else {
135
+ finishAction(instance, record, 'end');
136
+ }
137
+ }
138
+
139
+ function applySize(instance) {
140
+ instance._syncSizeAttribute();
141
+ instance._runtimeSizeApplied = instance.hasAttribute('size');
142
+ }
143
+
144
+ function hasVisibleLayout(instance) {
145
+ if (!instance.isConnected) return false;
146
+ const rects = instance.getClientRects?.();
147
+ if (!rects || rects.length === 0) return false;
148
+ const rect = instance.getBoundingClientRect();
149
+ return rect.width > 0 && rect.height > 0;
150
+ }
151
+
152
+ function cancelHeadAnimations(instance) {
153
+ const animations = instance._headMotion?.getAnimations?.() || [];
154
+ for (const animation of animations) animation.cancel();
155
+ if (instance._headMotion) instance._headMotion.style.transform = '';
156
+ }
157
+
158
+
159
+ function cancelContinuousMotion(instance) {
160
+ cancelHeadAnimations(instance);
161
+ instance._blinkAnim = null;
162
+ instance._blink = 1;
163
+ instance._boredRoutine = null;
164
+ instance._boredLookSpeed = null;
165
+ if (instance._wanderTarget) instance._wanderTarget.x = instance._wanderTarget.y = 0;
166
+ if (instance._wander) instance._wander.x = instance._wander.y = 0;
167
+ if (instance._look) instance._look.x = instance._look.y = 0;
168
+ }
169
+
170
+ function dragAtRest(drag) {
171
+ if (!drag || drag.active || drag.returning || drag.pendingReaction) return false;
172
+ return Math.abs(drag.x) < 0.0001 && Math.abs(drag.y) < 0.0001 &&
173
+ Math.abs(drag.vx) < 0.0001 && Math.abs(drag.vy) < 0.0001 &&
174
+ Math.abs(drag.stretch) < 0.0001 && Math.abs(drag.shear) < 0.0001 &&
175
+ Math.abs(drag.pullX) < 0.0001 && Math.abs(drag.pullY) < 0.0001;
176
+ }
177
+
178
+ function clearIdleDragVisuals(instance) {
179
+ if (!dragAtRest(instance._dragJelly)) return;
180
+ if (instance._dragMotion) {
181
+ instance._dragMotion.style.transform = '';
182
+ instance._dragMotion.style.transformOrigin = '';
183
+ }
184
+ if (instance._headShape && instance._baseHeadPathD) {
185
+ instance._headShape.setAttribute('d', instance._baseHeadPathD);
186
+ }
187
+ }
188
+
189
+ function clearAutoSleep(instance) {
190
+ if (!instance._runtimeAutoSleepTimer) return;
191
+ clearTimeout(instance._runtimeAutoSleepTimer);
192
+ instance._runtimeAutoSleepTimer = 0;
193
+ }
194
+
195
+ function autoSleepBlocked(instance) {
196
+ const record = instance._activeActionState;
197
+ return Boolean(
198
+ !instance.isConnected ||
199
+ instance._runtimeDisconnecting ||
200
+ instance._sleeping ||
201
+ (record && !record.terminal && record.source !== 'interaction') ||
202
+ instance._waitingRequested ||
203
+ instance._waitingFx ||
204
+ instance._inputWanted ||
205
+ instance._state === 'input' ||
206
+ instance._expressionLock ||
207
+ instance._gestureFx
208
+ );
209
+ }
210
+
211
+ function scheduleAutoSleep(instance) {
212
+ clearAutoSleep(instance);
213
+ const delayMs = Number(instance._autoSleepMs);
214
+ if (!Number.isFinite(delayMs) || delayMs <= 0 || autoSleepBlocked(instance)) return;
215
+ const remaining = Math.max(0, (instance._lastActivity + delayMs) - performance.now());
216
+ instance._runtimeAutoSleepTimer = setTimeout(() => {
217
+ instance._runtimeAutoSleepTimer = 0;
218
+ if (autoSleepBlocked(instance)) return;
219
+ const currentDelay = Number(instance._autoSleepMs);
220
+ if (!Number.isFinite(currentDelay) || currentDelay <= 0) return;
221
+ const nextRemaining = (instance._lastActivity + currentDelay) - performance.now();
222
+ if (nextRemaining > 1) {
223
+ scheduleAutoSleep(instance);
224
+ return;
225
+ }
226
+ const previousSource = instance._runtimeActionSource;
227
+ instance._runtimeActionSource = 'automatic';
228
+ try {
229
+ instance.sleep();
230
+ } finally {
231
+ instance._runtimeActionSource = previousSource;
232
+ }
233
+ }, remaining);
234
+ }
235
+
236
+ function requestVisualCommit(instance) {
237
+ if (!instance.isConnected || instance._runtimeDisconnecting) return;
238
+ instance._runtimeVisualDirty = true;
239
+ instance._resumeFrames?.();
240
+ }
241
+
242
+ function syncMotionPreference(instance) {
243
+ const reduced = reducedMotion(instance);
244
+ if (instance._runtimeLastReducedMotion === reduced) return reduced;
245
+ instance._runtimeLastReducedMotion = reduced;
246
+ instance._runtimeVisualDirty = true;
247
+ if (reduced) cancelContinuousMotion(instance);
248
+ return reduced;
249
+ }
250
+
251
+ function clearDragGeometry(instance, { preserveClick = false, releaseCapture = true } = {}) {
252
+ const drag = instance._dragJelly;
253
+ if (!drag) return;
254
+ const pointerId = drag.pointerId;
255
+ const suppressClick = preserveClick && drag.moved;
256
+
257
+ drag.active = false;
258
+ drag.returning = false;
259
+ drag.snapped = false;
260
+ drag.pointerId = null;
261
+ drag.pendingReaction = null;
262
+ drag.targetX = drag.targetY = drag.x = drag.y = drag.vx = drag.vy = 0;
263
+ drag.targetStretch = drag.stretch = drag.stretchVel = 0;
264
+ drag.targetShear = drag.shear = drag.shearVel = 0;
265
+ drag.targetPullX = drag.targetPullY = drag.pullX = drag.pullY = drag.pullVX = drag.pullVY = 0;
266
+ drag.angle = 0;
267
+ drag.maxDist = 0;
268
+ drag.ux = drag.uy = 0;
269
+ drag.anchorX = drag.anchorY = 50;
270
+ instance._pendingDragEvent = null;
271
+
272
+ if (releaseCapture && pointerId != null) {
273
+ try { instance.releasePointerCapture(pointerId); } catch (_) {}
274
+ }
275
+ if (instance._dragMotion) {
276
+ instance._dragMotion.style.transform = '';
277
+ instance._dragMotion.style.transformOrigin = '';
278
+ }
279
+ if (instance._headShape && instance._baseHeadPathD) {
280
+ instance._headShape.setAttribute('d', instance._baseHeadPathD);
281
+ }
282
+ instance._suppressClick = suppressClick;
283
+ }
284
+
285
+ function programActionOwnsExpression(instance) {
286
+ const record = instance._activeActionState;
287
+ if (record && !record.terminal && record.source !== 'interaction') return true;
288
+ return Boolean(
289
+ instance._waitingRequested ||
290
+ instance._waitingFx ||
291
+ instance._inputWanted ||
292
+ instance._inspectFx ||
293
+ instance._loveFx ||
294
+ instance._randomFx ||
295
+ instance._failureFx ||
296
+ instance._warningFx ||
297
+ instance._systemErrorShake ||
298
+ instance._sleeping ||
299
+ (instance._expressionLock && instance._state !== 'idle')
300
+ );
301
+ }
302
+
303
+ function startDragReaction(instance, reaction) {
304
+ if (!reaction || programActionOwnsExpression(instance)) return;
305
+ const result = reaction === 'angry'
306
+ ? instance.angry({ fromDrag: true })
307
+ : instance.success({ fromDrag: true });
308
+ const record = beginAction(instance, 'reaction', 'interaction', false);
309
+ trackFiniteAction(instance, record, result);
310
+ }
311
+
312
+ function finishDragReturn(instance, reaction) {
313
+ clearDragGeometry(instance, { preserveClick: true, releaseCapture: false });
314
+ startDragReaction(instance, reaction);
315
+ }
316
+
317
+ function applyDragTransform(instance) {
318
+ const drag = instance._dragJelly;
319
+ if (!drag) return;
320
+ instance._applyHeadDeform?.();
321
+ if (!instance._dragMotion) return;
322
+ const sx = 1 + drag.stretch;
323
+ const sy = 1 - drag.stretch * 0.30;
324
+ const shearDeg = drag.shear * 180 / Math.PI;
325
+ instance._dragMotion.style.transformOrigin = `${drag.anchorX.toFixed(2)}% ${drag.anchorY.toFixed(2)}%`;
326
+ instance._dragMotion.style.transform = `translate(${drag.x.toFixed(2)}px, ${drag.y.toFixed(2)}px) rotate(${drag.angle.toFixed(4)}rad) scale(${sx.toFixed(4)}, ${sy.toFixed(4)}) skewY(${shearDeg.toFixed(3)}deg) rotate(${(-drag.angle).toFixed(4)}rad)`;
327
+ }
328
+
329
+ function flushPointerWork(instance) {
330
+ const pointer = instance._pendingPointerEvent;
331
+ instance._pendingPointerEvent = null;
332
+ if (pointer) {
333
+ baseOnPointerMove.call(instance, pointer);
334
+ instance._runtimePointerFlushCount = (instance._runtimePointerFlushCount || 0) + 1;
335
+ }
336
+
337
+ const drag = instance._pendingDragEvent;
338
+ instance._pendingDragEvent = null;
339
+ if (drag && instance._dragJelly?.active && drag.pointerId === instance._dragJelly.pointerId) {
340
+ baseOnDragMove.call(instance, drag);
341
+ instance._runtimeDragFlushCount = (instance._runtimeDragFlushCount || 0) + 1;
342
+ }
343
+ }
344
+
345
+ function setRuntimeVisible(instance, visible) {
346
+ const next = visible === true;
347
+ if (instance._runtimeVisible === next) return;
348
+ instance._runtimeVisible = next;
349
+ if (!next) {
350
+ instance._cancelGesture?.();
351
+ if (instance._raf) cancelAnimationFrame(instance._raf);
352
+ instance._raf = 0;
353
+ instance._framePaused = true;
354
+ instance._pendingPointerEvent = null;
355
+ if (instance._dragJelly?.active || instance._dragJelly?.returning) {
356
+ clearDragGeometry(instance, { preserveClick: true });
357
+ }
358
+ cancelHeadAnimations(instance);
359
+ if (instance._antennaSpring) {
360
+ instance._antennaSpring.vx = 0;
361
+ instance._antennaSpring.vy = 0;
362
+ instance._antennaSpring.initialized = false;
363
+ }
364
+ return;
365
+ }
366
+ instance._resumeFrames?.();
367
+ }
368
+
369
+ function handleMotionChange(instance) {
370
+ const reduced = syncMotionPreference(instance);
371
+ if (reduced) {
372
+ cancelContinuousMotion(instance);
373
+ instance._pose = { ...instance._toPose };
374
+ instance._fromPose = { ...instance._toPose };
375
+ instance._morphDuration = 0;
376
+ if (instance._dragJelly?.returning) finishDragReturn(instance, instance._dragJelly.pendingReaction);
377
+ }
378
+ requestVisualCommit(instance);
379
+ scheduleAutoSleep(instance);
380
+ }
381
+
382
+ function ensureRuntime(instance) {
383
+ if (instance._runtimePolicyReady || !instance.isConnected || instance._runtimeDisconnecting) return;
384
+ instance._runtimePolicyReady = true;
385
+ if (!instance.style.touchAction) instance.style.touchAction = 'pinch-zoom';
386
+ applySize(instance);
387
+
388
+ if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
389
+ const query = window.matchMedia('(prefers-reduced-motion: reduce)');
390
+ const listener = () => handleMotionChange(instance);
391
+ instance._runtimeMotionQuery = query;
392
+ instance._runtimeMotionListener = listener;
393
+ if (query.addEventListener) query.addEventListener('change', listener);
394
+ else query.addListener?.(listener);
395
+ }
396
+
397
+ if (typeof MutationObserver !== 'undefined') {
398
+ instance._runtimeAttributeObserver = new MutationObserver(records => {
399
+ let motionChanged = false;
400
+ let autoSleepChanged = false;
401
+ for (const record of records) {
402
+ if (record.attributeName === 'size') applySize(instance);
403
+ if (record.attributeName === 'motion') motionChanged = true;
404
+ if (record.attributeName === 'auto-sleep') autoSleepChanged = true;
405
+ }
406
+ if (motionChanged) handleMotionChange(instance);
407
+ if (autoSleepChanged) scheduleAutoSleep(instance);
408
+ });
409
+ instance._runtimeAttributeObserver.observe(instance, {
410
+ attributes: true,
411
+ attributeFilter: ['size', 'motion', 'wake-on', 'auto-sleep'],
412
+ });
413
+ }
414
+
415
+ if (typeof IntersectionObserver !== 'undefined') {
416
+ instance._runtimeIntersectionObserver = new IntersectionObserver(entries => {
417
+ const entry = entries[entries.length - 1];
418
+ if (!entry) return;
419
+ instance._runtimeIntersecting = entry.isIntersecting;
420
+ setRuntimeVisible(instance, entry.isIntersecting && hasVisibleLayout(instance));
421
+ });
422
+ instance._runtimeIntersectionObserver.observe(instance);
423
+ }
424
+
425
+ if (typeof ResizeObserver !== 'undefined') {
426
+ instance._runtimeResizeObserver = new ResizeObserver(() => {
427
+ const inView = instance._runtimeIntersecting !== false;
428
+ setRuntimeVisible(instance, inView && hasVisibleLayout(instance));
429
+ });
430
+ instance._runtimeResizeObserver.observe(instance);
431
+ }
432
+
433
+ instance._runtimeVisible = hasVisibleLayout(instance);
434
+ instance._runtimeLostCapture = event => {
435
+ if (instance._gestureFx?.held && event.pointerId === instance._gestureFx.pointerId) {
436
+ instance._cancelGesture?.();
437
+ }
438
+ if (instance._dragJelly?.active && event.pointerId === instance._dragJelly.pointerId) {
439
+ clearDragGeometry(instance, { preserveClick: false, releaseCapture: false });
440
+ }
441
+ };
442
+ instance.addEventListener('lostpointercapture', instance._runtimeLostCapture);
443
+
444
+ if (!instance._runtimeLoopWrapped && typeof instance._loop === 'function') {
445
+ const loop = instance._loop;
446
+ instance._loop = ts => {
447
+ flushPointerWork(instance);
448
+ return loop(ts);
449
+ };
450
+ instance._runtimeLoopWrapped = true;
451
+ }
452
+ scheduleAutoSleep(instance);
453
+ }
454
+
455
+ function teardownRuntime(instance) {
456
+ clearAutoSleep(instance);
457
+ cancelContinuousMotion(instance);
458
+ instance._runtimeIntersectionObserver?.disconnect();
459
+ instance._runtimeResizeObserver?.disconnect();
460
+ instance._runtimeAttributeObserver?.disconnect();
461
+ if (instance._runtimeMotionQuery && instance._runtimeMotionListener) {
462
+ if (instance._runtimeMotionQuery.removeEventListener) {
463
+ instance._runtimeMotionQuery.removeEventListener('change', instance._runtimeMotionListener);
464
+ } else {
465
+ instance._runtimeMotionQuery.removeListener?.(instance._runtimeMotionListener);
466
+ }
467
+ }
468
+ if (instance._runtimeLostCapture) {
469
+ instance.removeEventListener('lostpointercapture', instance._runtimeLostCapture);
470
+ }
471
+ instance._runtimeIntersectionObserver = null;
472
+ instance._runtimeResizeObserver = null;
473
+ instance._runtimeAttributeObserver = null;
474
+ instance._runtimeMotionQuery = null;
475
+ instance._runtimeMotionListener = null;
476
+ instance._runtimeLostCapture = null;
477
+ instance._runtimePolicyReady = false;
478
+ instance._runtimeVisible = false;
479
+ instance._runtimeLastReducedMotion = undefined;
480
+ instance._runtimeVisualDirty = false;
481
+ instance._pendingPointerEvent = null;
482
+ instance._pendingDragEvent = null;
483
+ }
484
+
485
+ function eventTargetsAvatar(event, instance) {
486
+ const path = event?.composedPath?.();
487
+ if (Array.isArray(path)) return path.includes(instance);
488
+ return event?.target === instance || instance.contains?.(event?.target);
489
+ }
490
+
491
+ proto._isReducedMotion = function() {
492
+ return reducedMotion(this);
493
+ };
494
+
495
+ proto.noteActivity = function(wake = true) {
496
+ ensureRuntime(this);
497
+ const shouldWake = wake !== false && (this._sleeping || this._state === 'sleep');
498
+ const result = baseNoteActivity.call(this, false);
499
+ scheduleAutoSleep(this);
500
+ if (shouldWake) this.wake();
501
+ return result;
502
+ };
503
+
504
+ proto._noteEnvironmentActivity = function(event) {
505
+ ensureRuntime(this);
506
+ const shouldConsiderWake = this._sleeping || this._state === 'sleep';
507
+ const result = baseNoteActivity.call(this, false);
508
+ scheduleAutoSleep(this);
509
+ if (!shouldConsiderWake) return result;
510
+
511
+ const policy = wakePolicy(this);
512
+ const shouldWake = policy === 'activity' || (policy === 'interaction' && eventTargetsAvatar(event, this));
513
+ if (!shouldWake) return result;
514
+
515
+ const previousSource = this._runtimeActionSource;
516
+ this._runtimeActionSource = 'automatic';
517
+ try {
518
+ return this.wake();
519
+ } finally {
520
+ this._runtimeActionSource = previousSource;
521
+ }
522
+ };
523
+
524
+ proto._resetToIdle = function(notify = true) {
525
+ const previous = this._runtimeResetNotify;
526
+ this._runtimeResetNotify = notify;
527
+ try {
528
+ return baseResetToIdle.call(this, notify);
529
+ } finally {
530
+ this._runtimeResetNotify = previous;
531
+ scheduleAutoSleep(this);
532
+ }
533
+ };
534
+
535
+ proto._startMorph = function(target, duration, ease) {
536
+ const reduced = reducedMotion(this);
537
+ const result = baseStartMorph.call(this, target, reduced ? 0 : duration, ease);
538
+ if (reduced) requestVisualCommit(this);
539
+ return result;
540
+ };
541
+
542
+ proto._animateHead = function(frames, duration) {
543
+ if (reducedMotion(this)) {
544
+ cancelHeadAnimations(this);
545
+ return undefined;
546
+ }
547
+ return baseAnimateHead.call(this, frames, duration);
548
+ };
549
+
550
+ proto._updateBlink = function(now) {
551
+ if (!reducedMotion(this)) return baseUpdateBlink.call(this, now);
552
+ this._blinkAnim = null;
553
+ this._blink = 1;
554
+ };
555
+
556
+ proto._updateLook = function(now, dt) {
557
+ if (!reducedMotion(this)) return baseUpdateLook.call(this, now, dt);
558
+ this._boredRoutine = null;
559
+ this._boredLookSpeed = null;
560
+ this._wanderTarget.x = this._wanderTarget.y = 0;
561
+ this._wander.x = this._wander.y = 0;
562
+ this._look.x = this._look.y = 0;
563
+ };
564
+
565
+ proto._updateHeadFollow = function(now, dt) {
566
+ if (!reducedMotion(this)) return baseUpdateHeadFollow.call(this, now, dt);
567
+ this._headFollowPose.x = this._headFollowPose.y = this._headFollowPose.rot = 0;
568
+ this._headFollowVel.x = this._headFollowVel.y = this._headFollowVel.rot = 0;
569
+ if (this._headFollow) this._headFollow.setAttribute('transform', '');
570
+ };
571
+
572
+ proto._updateDragJelly = function(dt) {
573
+ const drag = this._dragJelly;
574
+ if (!reducedMotion(this)) {
575
+ const result = baseUpdateDragJelly.call(this, dt);
576
+ clearIdleDragVisuals(this);
577
+ return result;
578
+ }
579
+ if (!drag) return;
580
+ if (drag.active) {
581
+ drag.x = drag.targetX;
582
+ drag.y = drag.targetY;
583
+ drag.stretch = drag.targetStretch;
584
+ drag.shear = drag.targetShear;
585
+ drag.pullX = drag.targetPullX;
586
+ drag.pullY = drag.targetPullY;
587
+ applyDragTransform(this);
588
+ } else if (drag.returning) {
589
+ finishDragReturn(this, drag.pendingReaction);
590
+ }
591
+ clearIdleDragVisuals(this);
592
+ };
593
+
594
+ proto._onPointerMove = function(event) {
595
+ ensureRuntime(this);
596
+ if (this._runtimeVisible === false) return;
597
+ this._pendingPointerEvent = {
598
+ clientX: event.clientX,
599
+ clientY: event.clientY,
600
+ };
601
+ this._resumeFrames?.();
602
+ };
603
+
604
+ proto._onDragMove = function(event) {
605
+ ensureRuntime(this);
606
+ if (this._gestureFx) {
607
+ this._moveGesture(event);
608
+ return;
609
+ }
610
+ if (!this._dragJelly?.active || event.pointerId !== this._dragJelly.pointerId) return;
611
+ this._pendingDragEvent = {
612
+ clientX: event.clientX,
613
+ clientY: event.clientY,
614
+ pointerId: event.pointerId,
615
+ };
616
+ this._resumeFrames?.();
617
+ };
618
+
619
+ proto._onDragStart = function(event) {
620
+ ensureRuntime(this);
621
+ if (this._dragJelly?.active) return;
622
+ if (event.pointerType === 'touch' && event.isPrimary === false) return;
623
+ if (this._gestureFx?.held) return;
624
+ if (this._startGesture?.(event)) return;
625
+ return baseOnDragStart.call(this, event);
626
+ };
627
+
628
+ proto._startHeadDragFromGesture = function(event, start) {
629
+ baseOnDragStart.call(this, {
630
+ button: 0,
631
+ clientX: start.startX,
632
+ clientY: start.startY,
633
+ pointerId: event.pointerId,
634
+ pointerType: start.pointerType,
635
+ });
636
+ baseOnDragMove.call(this, event);
637
+ };
638
+
639
+ proto._beginGestureAction = function(kind) {
640
+ beginAction(this, kind, 'interaction', true);
641
+ };
642
+ proto._endGestureAction = function(phase, react = false, silent = false) {
643
+ const record = this._activeActionState;
644
+ if (record && (record.action === 'squeeze' || record.action === 'antenna-drag')) {
645
+ if (silent) cancelActiveAction(this, { silent: true });
646
+ else finishAction(this, record, phase);
647
+ }
648
+ if (react) startDragReaction(this, 'angry');
649
+ };
650
+
651
+ proto._onDragEnd = function(event) {
652
+ if (this._gestureFx) {
653
+ this._endGesture(event);
654
+ return;
655
+ }
656
+ const drag = this._dragJelly;
657
+ if (!drag?.active || event.pointerId !== drag.pointerId) return;
658
+ flushPointerWork(this);
659
+ if (event.type === 'pointercancel') {
660
+ clearDragGeometry(this, { preserveClick: false });
661
+ return;
662
+ }
663
+ baseOnDragEnd.call(this, event);
664
+ if (reducedMotion(this) && drag.returning) finishDragReturn(this, drag.pendingReaction);
665
+ };
666
+
667
+ proto._finishDragReturn = function(reaction) {
668
+ finishDragReturn(this, reaction);
669
+ };
670
+
671
+ proto._resumeFrames = function() {
672
+ if (!this.isConnected || this._runtimeDisconnecting) return;
673
+ ensureRuntime(this);
674
+ if (this._runtimeVisible === false) return;
675
+ if (syncMotionPreference(this)) this._runtimeVisualDirty = true;
676
+ return baseResumeFrames.call(this);
677
+ };
678
+
679
+ proto._draw = function(now) {
680
+ syncMotionPreference(this);
681
+ const result = baseDraw.call(this, now);
682
+ this._runtimeVisualDirty = false;
683
+ return result;
684
+ };
685
+
686
+ proto._canPauseFrames = function(now) {
687
+ if (this._runtimeVisible === false) return true;
688
+ const reduced = syncMotionPreference(this);
689
+ if (!reduced) return baseCanPauseFrames.call(this, now);
690
+ if (this._pendingPointerEvent || this._pendingDragEvent || this._runtimeVisualDirty) return false;
691
+ return true;
692
+ };
693
+
694
+ function playNoOp(instance, canonical) {
695
+ if (canonical === 'wake') return !instance._sleeping && instance._state !== 'sleep';
696
+ if (canonical === 'sleep') return instance._sleeping === true;
697
+ if (canonical === 'input') return instance._inputWanted || instance._state === 'input';
698
+ return false;
699
+ }
700
+
701
+ function leaveSleepForAction(instance) {
702
+ if (!instance._sleeping && instance._state !== 'sleep') return;
703
+ instance._sleeping = false;
704
+ instance.setState('idle', { duration: reducedMotion(instance) ? 0 : 120 });
705
+ }
706
+
707
+ function prepareReplacement(instance, canonical) {
708
+ instance._cancelGesture?.();
709
+ clearAutoSleep(instance);
710
+ cancelActiveAction(instance);
711
+ clearDragGeometry(instance, { preserveClick: true });
712
+ instance._cancelPendingWaits?.();
713
+ if (canonical !== 'sleep' && canonical !== 'wake' && canonical !== 'idle') {
714
+ leaveSleepForAction(instance);
715
+ }
716
+ }
717
+
718
+ proto.play = function(name) {
719
+ ensureRuntime(this);
720
+ const { raw, canonical } = normalizeAction(name);
721
+ if (!canonical) throw new Error(`Unknown Agent Robot Avatar action: ${name}`);
722
+ if (playNoOp(this, canonical)) return this;
723
+ if (canonical === 'idle') return basePlay.call(this, raw);
724
+
725
+ prepareReplacement(this, canonical);
726
+
727
+ let result;
728
+ this._runtimeInPlay = true;
729
+ try {
730
+ result = basePlay.call(this, raw);
731
+ } finally {
732
+ this._runtimeInPlay = false;
733
+ }
734
+
735
+ const record = beginAction(this, canonical, 'api', canonical === 'input');
736
+ trackFiniteAction(this, record, result);
737
+ if (reducedMotion(this)) queueMicrotask(() => cancelHeadAnimations(this));
738
+ return result;
739
+ };
740
+
741
+ proto.input = function(active = true) {
742
+ if (this._runtimeInPlay) return baseInput.call(this, active);
743
+ ensureRuntime(this);
744
+ if (active) {
745
+ if (this._inputWanted || this._state === 'input') return this;
746
+ prepareReplacement(this, 'input');
747
+ const result = baseInput.call(this, true);
748
+ beginAction(this, 'input', 'api', true);
749
+ return result;
750
+ }
751
+
752
+ const record = this._activeActionState?.action === 'input' ? this._activeActionState : null;
753
+ const result = baseInput.call(this, false);
754
+ if (record) finishAction(this, record, 'end');
755
+ return result;
756
+ };
757
+
758
+ proto.startWaiting = async function(options = {}) {
759
+ ensureRuntime(this);
760
+ clearAutoSleep(this);
761
+ const result = await baseStartWaiting.call(this, options);
762
+ if (this._waitingRequested && this._waitingFx) beginAction(this, 'waiting', 'api', true);
763
+ return result;
764
+ };
765
+
766
+ proto.stopWaiting = function() {
767
+ ensureRuntime(this);
768
+ const record = this._activeActionState?.action === 'waiting' ? this._activeActionState : null;
769
+ this._runtimeEndingWaiting = Boolean(record);
770
+ let result;
771
+ try {
772
+ result = baseStopWaiting.call(this);
773
+ } finally {
774
+ this._runtimeEndingWaiting = false;
775
+ }
776
+ if (record) finishAction(this, record, 'end');
777
+ return result;
778
+ };
779
+
780
+ proto.sleep = function() {
781
+ if (this._runtimeInPlay) return baseSleep.call(this);
782
+ ensureRuntime(this);
783
+ if (this._sleeping) return this;
784
+ prepareReplacement(this, 'sleep');
785
+ const source = this._runtimeActionSource || 'api';
786
+ const result = baseSleep.call(this);
787
+ const record = beginAction(this, 'sleep', source, false);
788
+ trackFiniteAction(this, record, result);
789
+ return result;
790
+ };
791
+
792
+ proto.wake = function() {
793
+ if (this._runtimeInPlay) return baseWake.call(this);
794
+ ensureRuntime(this);
795
+ if (!this._sleeping && this._state !== 'sleep') return this;
796
+ prepareReplacement(this, 'wake');
797
+ const source = this._runtimeActionSource || 'api';
798
+ const result = baseWake.call(this);
799
+ const record = beginAction(this, 'wake', source, false);
800
+ trackFiniteAction(this, record, result);
801
+ return result;
802
+ };
803
+
804
+ proto._autoSleep = function() {
805
+ // Auto-sleep is scheduled independently from drawing by scheduleAutoSleep().
806
+ };
807
+
808
+ proto._scheduleAutoSleep = function() {
809
+ scheduleAutoSleep(this);
810
+ };
811
+
812
+ proto._teardownRuntime = function() {
813
+ teardownRuntime(this);
814
+ };
815
+
816
+ function setMask(top, bottom, topY, bottomY, topAngle = 0, bottomAngle = 0) {
817
+ if (top) {
818
+ top.setAttribute('y', (topY - 90).toFixed(2));
819
+ top.setAttribute('height', '90');
820
+ top.setAttribute('transform', `rotate(${topAngle.toFixed(2)} 0 ${topY.toFixed(2)})`);
821
+ }
822
+ if (bottom) {
823
+ bottom.setAttribute('y', bottomY.toFixed(2));
824
+ bottom.setAttribute('height', '90');
825
+ bottom.setAttribute('transform', `rotate(${bottomAngle.toFixed(2)} 0 ${bottomY.toFixed(2)})`);
826
+ }
827
+ }
828
+
829
+ function setEye(eye, x, y = 126, sx = 1, sy = 1) {
830
+ if (eye) eye.setAttribute('transform', `translate(${x.toFixed(2)} ${y.toFixed(2)}) scale(${sx.toFixed(3)} ${sy.toFixed(3)})`);
831
+ }
832
+
833
+ function drawReducedState(instance) {
834
+ if (!reducedMotion(instance)) return;
835
+ if (instance._state === 'input') {
836
+ instance._leftInputBase?.setAttribute('opacity', '1');
837
+ instance._rightInputBase?.setAttribute('opacity', '1');
838
+ }
839
+ if (instance._antennaDot) instance._antennaDot.style.opacity = '1';
840
+
841
+ if (instance._waitingFx) {
842
+ setEye(instance._leftEye, 100, 126, 0.92, 1);
843
+ setEye(instance._rightEye, 140, 126, 0.92, 1);
844
+ return;
845
+ }
846
+ if (instance._inspectFx) {
847
+ setEye(instance._leftEye, 86);
848
+ setEye(instance._rightEye, 154);
849
+ setMask(instance._leftTop, instance._leftBottom, -8, 8);
850
+ setMask(instance._rightTop, instance._rightBottom, -8, 8);
851
+ return;
852
+ }
853
+ if (instance._warningFx) {
854
+ setEye(instance._leftEye, 100, 126, 1.16, 1.10);
855
+ setEye(instance._rightEye, 172, 132, 0.84, 0.96);
856
+ setMask(instance._leftTop, instance._leftBottom, -18, 35, 8, 0);
857
+ setMask(instance._rightTop, instance._rightBottom, -20, 36, -7, 0);
858
+ return;
859
+ }
860
+ if (instance._systemErrorShake) {
861
+ setMask(instance._leftTop, instance._leftBottom, -5, 36, -15, 0);
862
+ setMask(instance._rightTop, instance._rightBottom, -5, 36, 15, 0);
863
+ }
864
+ }
865
+
866
+ for (const property of ['_waitingFx', '_inspectFx', '_loveFx', '_randomFx', '_failureFx', '_warningFx', '_systemErrorShake']) {
867
+ const slot = Symbol(property);
868
+ Object.defineProperty(proto, property, {
869
+ configurable: true,
870
+ get() { return this[slot]; },
871
+ set(value) {
872
+ this[slot] = value;
873
+ this._runtimeVisualDirty = true;
874
+ if (this.isConnected && !this._runtimeDisconnecting && syncMotionPreference(this)) {
875
+ requestVisualCommit(this);
876
+ queueMicrotask(() => {
877
+ if (this.isConnected && !this._runtimeDisconnecting && syncMotionPreference(this)) {
878
+ cancelContinuousMotion(this);
879
+ }
880
+ });
881
+ }
882
+ },
883
+ });
884
+ }
885
+
886
+ registerAvatarExtension({
887
+ name: 'runtime-policy',
888
+ reset() {
889
+ const silent = this._runtimeResetNotify === false;
890
+ if (!this._runtimeEndingWaiting) cancelActiveAction(this, { silent });
891
+ clearDragGeometry(this, { preserveClick: !silent });
892
+ this._pendingPointerEvent = null;
893
+ },
894
+ draw() {
895
+ ensureRuntime(this);
896
+ drawReducedState(this);
897
+ },
898
+ });
899
+
900
+ export {
901
+ AgentRobotAvatar,
902
+ ACTION_ALIASES,
903
+ DEFAULT_SIZE,
904
+ };
905
+ export default AgentRobotAvatar;