diff --git a/pkg/miniapp/static/index.html b/pkg/miniapp/static/index.html index b6af8616c..410daa7db 100644 --- a/pkg/miniapp/static/index.html +++ b/pkg/miniapp/static/index.html @@ -1920,22 +1920,33 @@ function _orchConverse(fromId, toId, text) { function _orchUpdate(dt) { _orchAllChars().forEach(function(c){ if (!c.alive && c.state!=='entering') return; - c.frameTimer+=dt; - var dur=_orchFRAME_MS[c.state]||450; - if (c.frameTimer>=dur){ c.frame=(c.frame+1)%4; c.frameTimer-=dur; } + // Frame animation (bob): pigeon uses state-specific timing instead of shared table. + if (c === _orchHeartbeat) { + if (c.state === 'idle') { + c.frame = 0; // pin still — no bob when inactive + } else { + c.frameTimer += dt; + var pDur = c.state==='toolcall' ? 130 : 380; + if (c.frameTimer >= pDur) { c.frame=(c.frame+1)%4; c.frameTimer-=pDur; } + } + } else { + c.frameTimer+=dt; + var dur=_orchFRAME_MS[c.state]||450; + if (c.frameTimer>=dur){ c.frame=(c.frame+1)%4; c.frameTimer-=dur; } + } if (c.target){ var dx=c.target.x-c.x, dy=c.target.y-c.y, dist=Math.sqrt(dx*dx+dy*dy); if (dist>1.5){ var spd=_orchWALK*dt/1000; c.x+=dx/dist*spd; c.y+=dy/dist*spd; } else { c.x=c.target.x; c.y=c.target.y; c.target=null; if(c._onArrive){c._onArrive();c._onArrive=null;} } } if (c.bubble){ c.bubble.ttl-=dt; if(c.bubble.ttl<=0) c.bubble=null; } - // Heartbeat pigeon: face movement direction; flip periodically when stationary. + // Heartbeat pigeon: direction flip rate reflects activity level. if (c === _orchHeartbeat) { if (c.target) { var pdx = c.target.x - c.x; if (Math.abs(pdx) > 1) c.facing = pdx > 0 ? 1 : -1; } else { - var flipRate = c.state==='toolcall' ? 280 : c.state==='waiting' ? 480 : 720; + var flipRate = c.state==='toolcall' ? 280 : c.state==='waiting' ? 600 : 2800; c.flipTimer += dt; if (c.flipTimer >= flipRate) { c.flipTimer -= flipRate; c.facing = -c.facing; } }