feat(miniapp): pigeon activity reflects heartbeat session state

idle:     frame pinned to 0 (no bob), flip every ~2.8s — sitting still
waiting:  bob at 380ms/frame, flip every ~600ms — gentle activity
toolcall: bob at 130ms/frame, flip every ~280ms — visibly busy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dj-oyu 2026-02-25 12:12:21 +09:00
parent cf3931ad3b
commit d429256395

View file

@ -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; }
}