From 5ea06a2d06a1391d6ca309e6aaa3b358caac3f22 Mon Sep 17 00:00:00 2001 From: OpenClaw Assistant Date: Wed, 4 Mar 2026 16:43:44 +0800 Subject: [PATCH] fix(status-sync): force visual state reconciliation on every poll and reduce status polling interval --- frontend/index.html | 163 ++++++++++++++++++++++---------------------- 1 file changed, 83 insertions(+), 80 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 9a34986..640cd51 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1682,7 +1682,7 @@ let guestTweens = {}; // agentId -> {move, name} let hiddenDemoNames = new Set(); const DEMO_MODE = new URLSearchParams(window.location.search).get('demo') === '1'; - const FETCH_INTERVAL = 2000; + const FETCH_INTERVAL = 1000; const GUEST_AGENTS_FETCH_INTERVAL = 3500; const BLINK_INTERVAL = 2500; const BUBBLE_INTERVAL = 8000; @@ -4491,6 +4491,81 @@ function toggleBrokerPanel() { return s; } + function applyVisualState(nextState) { + // Idle: show Star idle animation (main character) + if (nextState === 'idle') { + sofa.anims.stop(); + sofa.setTexture('sofa_idle'); + + if (window.starWorking) { + window.starWorking.setVisible(false); + window.starWorking.anims.stop(); + } + + star.setVisible(true); + star.setScale(IDLE_STAR_SCALE); + star.anims.play('star_idle', true); + star.setPosition(IDLE_SOFA_ANCHOR.x, IDLE_SOFA_ANCHOR.y); + } else if (nextState === 'error') { + // Error: no working animation at desk + sofa.anims.stop(); + sofa.setTexture('sofa_idle'); + star.setVisible(false); + star.anims.stop(); + if (window.starWorking) { + window.starWorking.setVisible(false); + window.starWorking.anims.stop(); + } + } else if (nextState === 'syncing') { + // Syncing: also no working animation at desk + sofa.anims.stop(); + sofa.setTexture('sofa_idle'); + star.setVisible(false); + star.anims.stop(); + if (window.starWorking) { + window.starWorking.setVisible(false); + window.starWorking.anims.stop(); + } + } else { + // Non-idle non-error: starWorking animation at desk + sofa.anims.stop(); + sofa.setTexture('sofa_idle'); + // Hide moving star, show desk star + star.setVisible(false); + star.anims.stop(); + if (window.starWorking) { + window.starWorking.setVisible(true); + window.starWorking.anims.play('star_working', true); + } + } + + // Server room logic + if (serverroom) { + if (nextState === 'idle') { + serverroom.anims.stop(); + serverroom.setFrame(0); + } else { + serverroom.anims.play('serverroom_on', true); + } + } + + // Sync animation logic: default frame0; syncing play loop + if (syncAnimSprite) { + if (nextState === 'syncing') { + if (syncAnimPlayable && syncAnimSprite.anims && syncAnimSprite.anims.play && syncAnimSprite.scene?.anims?.exists('sync_anim')) { + if (!syncAnimSprite.anims.isPlaying || syncAnimSprite.anims.currentAnim?.key !== 'sync_anim') { + syncAnimSprite.anims.play('sync_anim', true); + } + } else { + syncAnimSprite.setFrame(0); + } + } else { + if (syncAnimSprite.anims && syncAnimSprite.anims.isPlaying) syncAnimSprite.anims.stop(); + syncAnimSprite.setFrame(0); + } + } + } + function fetchStatus() { return fetch('/status', { cache: 'no-store' }) .then(response => response.json()) @@ -4501,89 +4576,17 @@ function toggleBrokerPanel() { // If we're mid-transition, don't restart the path every poll const changed = (pendingDesiredState === null) && (nextState !== currentState); const nextLine = '[' + stateInfo.name + '] ' + (data.detail || '...'); + // 不论 changed 与否,都按服务端最新状态强制一次视觉同步,避免动画卡旧状态 + pendingDesiredState = null; + if (currentState !== nextState) { + currentState = nextState; + } + applyVisualState(nextState); + if (changed) { typewriterTarget = nextLine; typewriterText = ''; typewriterIndex = 0; - - // Set state immediately (no waypoints/path movement) - pendingDesiredState = null; - currentState = nextState; - - // Idle: show Star idle animation (main character) - if (nextState === 'idle') { - sofa.anims.stop(); - sofa.setTexture('sofa_idle'); - - if (window.starWorking) { - window.starWorking.setVisible(false); - window.starWorking.anims.stop(); - } - - star.setVisible(true); - star.setScale(IDLE_STAR_SCALE); - star.anims.play('star_idle', true); - star.setPosition(IDLE_SOFA_ANCHOR.x, IDLE_SOFA_ANCHOR.y); - } else if (nextState === 'error') { - // Error: no working animation at desk - sofa.anims.stop(); - sofa.setTexture('sofa_idle'); - star.setVisible(false); - star.anims.stop(); - if (window.starWorking) { - window.starWorking.setVisible(false); - window.starWorking.anims.stop(); - } - } else if (nextState === 'syncing') { - // Syncing: also no working animation at desk - sofa.anims.stop(); - sofa.setTexture('sofa_idle'); - star.setVisible(false); - star.anims.stop(); - if (window.starWorking) { - window.starWorking.setVisible(false); - window.starWorking.anims.stop(); - } - } else { - // Non-idle non-error: starWorking animation at desk - sofa.anims.stop(); - sofa.setTexture('sofa_idle'); - // Hide moving star, show desk star - star.setVisible(false); - star.anims.stop(); - if (window.starWorking) { - window.starWorking.setVisible(true); - window.starWorking.anims.play('star_working', true); - } - } - - // Server room logic: - if (serverroom) { - if (nextState === 'idle') { - serverroom.anims.stop(); - serverroom.setFrame(0); - } else { - serverroom.anims.play('serverroom_on', true); - } - } - - // Sync animation logic: - // default: frame 0 - // state=syncing: play from frame 1 - if (syncAnimSprite) { - if (nextState === 'syncing') { - if (syncAnimPlayable && syncAnimSprite.anims && syncAnimSprite.anims.play && syncAnimSprite.scene?.anims?.exists('sync_anim')) { - if (!syncAnimSprite.anims.isPlaying || syncAnimSprite.anims.currentAnim?.key !== 'sync_anim') { - syncAnimSprite.anims.play('sync_anim', true); - } - } else { - syncAnimSprite.setFrame(0); - } - } else { - if (syncAnimSprite.anims && syncAnimSprite.anims.isPlaying) syncAnimSprite.anims.stop(); - syncAnimSprite.setFrame(0); - } - } } else { if (!typewriterTarget || typewriterTarget !== nextLine) { typewriterTarget = nextLine;