@bitefoundry/retrieviewer 0.0.14 → 0.0.16
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.
- package/ASSET-PROVENANCE.md +13 -0
- package/ATTENTION-PAW.md +53 -0
- package/ATTENTION-WALL.md +58 -0
- package/ATTENTION.md +44 -3
- package/BRAIN.md +18 -8
- package/README.ko.md +6 -0
- package/README.md +9 -0
- package/RELEASING.md +36 -1
- package/integrations/stackbite/attention.mjs +22 -5
- package/integrations/windows-overlay/Overlay.cs +19 -7
- package/integrations/windows-overlay/worker.mjs +4 -3
- package/package.json +3 -1
- package/puppy-comfort-sprites.mjs +10 -4
- package/puppy-companion-comfort-q5.bin.gz +0 -0
- package/puppy-companion-comfort.json +818 -5
- package/puppy-companion-life.mjs +18 -6
- package/puppy-motion-tables.generated.mjs +1 -1
- package/puppy-paper.mjs +11 -3
- package/retrieviewer-attention.d.mts +5 -3
- package/retrieviewer-attention.mjs +30 -22
- package/retrieviewer.d.mts +2 -2
package/puppy-companion-life.mjs
CHANGED
|
@@ -19,6 +19,7 @@ const CARRY_HEIGHT=.19,SETTLE_FALLBACK=.6,MAX_DT=.25,ARRIVE=.05;
|
|
|
19
19
|
// Active simulation seconds, never a wall-clock timer that wakes a hidden pet.
|
|
20
20
|
export const BUTTERFLY_RULES=Object.freeze({firstMin:240,firstSpread:240,cooldownMin:720,cooldownSpread:480,maxVisible:18});
|
|
21
21
|
const LABEL={
|
|
22
|
+
notifyWall:'뒷발로 서서 벽을 박박 긁는 중',
|
|
22
23
|
start:'기다리는 중',pause:'잠시 느긋하게 둘러보는 중',lie:'엎드리는 중',rest:'엎드려 쉬는 중',recover:'앉아서 기운 차리는 중',
|
|
23
24
|
sit:'앉는 중',watch:'앉아서 지켜보는 중',look:'고개를 돌려 살피는 중',observe:'가만히 주변 관찰 중',
|
|
24
25
|
stroll:'옆으로 살짝 걸어가는 중',sniff:'잠깐 멈춰 주변을 살피는 중',dash:'저 멀리 달려가는 중',far:'멀리서 둘러보는 중',home:'제자리로 돌아오는 중',nest:'쉴 자리를 찾아가는 중',
|
|
@@ -26,7 +27,7 @@ const LABEL={
|
|
|
26
27
|
belly:'배를 보이고 발라당 쉬는 중',sleep:'새근새근 잠자는 중',tug:'장난감을 물고 당기는 중',
|
|
27
28
|
butterflyNotice:'나비를 발견하고 귀를 쫑긋하는 중',butterfly:'나비를 폴짝폴짝 쫓는 중',butterflyBye:'날아가는 나비를 바라보는 중',
|
|
28
29
|
fetch:'공을 쫓아가는 중',miss:'굴러가는 공을 한 번 놓친 중',reChase:'공을 다시 쫓아가는 중',tumble:'우당탕 균형을 되찾는 중',pickup:'공을 무는 중',carry:'공을 물고 돌아오는 중',drop:'공을 내려놓는 중',offer:'공을 내려놓고 기다리는 중',
|
|
29
|
-
treatSit:'간식 앞에 앉는 중',chew:'간식 먹는 중',notifySit:'확인할 일을 발견하고 앉는 중',notify:'확인할 일이 있는 쪽을 바라보는 중'
|
|
30
|
+
treatSit:'간식 앞에 앉는 중',chew:'간식 먹는 중',notifySit:'확인할 일을 발견하고 앉는 중',notifyContact:'확인할 일이 있어 사용자를 바라보는 중',notifyCome:'확인할 일을 알려주러 가까이 오는 중',notifyPaw:'앞발로 살살 관심을 끄는 중',notify:'확인할 일이 있는 쪽을 바라보는 중'
|
|
30
31
|
};
|
|
31
32
|
const PENDING_LABEL={treat:'곧 간식',tug:'곧 터그놀이'};
|
|
32
33
|
// Baked interaction clips, played only while holding at the shared seated endpoint.
|
|
@@ -62,7 +63,7 @@ export function createCompanionLife(actor,{seed=731,energy=.8,returnStyle='auto'
|
|
|
62
63
|
let clock=0,decisions=0,lastEpisode=null,quiet=0;
|
|
63
64
|
let queue=[],hold=0,holdIntent=null,waiting=null,gesture=null;
|
|
64
65
|
let intent='start',label=LABEL.start,pending=null,active=null,ball=null,treat=null;
|
|
65
|
-
let fetchPlan=null,notice=null;
|
|
66
|
+
let fetchPlan=null,notice=null,noticeCount=0;
|
|
66
67
|
|
|
67
68
|
const cmd=(name,args,step,when)=>({cmd:name,args,intent:step,label:LABEL[step],when});
|
|
68
69
|
const wait=(seconds,step)=>({hold:seconds,intent:step,label:LABEL[step]});
|
|
@@ -238,7 +239,12 @@ export function createCompanionLife(actor,{seed=731,energy=.8,returnStyle='auto'
|
|
|
238
239
|
if(pending&&!active)startInteraction();
|
|
239
240
|
if(notice?.phase==='queued'&&!active&&!pending){
|
|
240
241
|
notice.phase='showing';
|
|
241
|
-
|
|
242
|
+
const far=()=>{const s=actor.sample(clock);return Math.hypot(s.x-HOME.x,s.z-HOME.z)>.8;};
|
|
243
|
+
queue=[sit('notifySit'),wait(.45,'notifyContact'),
|
|
244
|
+
fx(()=>{if(far())notice.phase='approaching';}),cmd('go',[HOME.x,HOME.z],'notifyCome',far),
|
|
245
|
+
sit('notifySit'),fx(()=>{notice.phase='showing';}),wait(.6,'notifyContact'),
|
|
246
|
+
...(notice.gesture==='wall'?[cmd('attentionWall',[],'notifyWall'),wait(.3,'notifyContact')]:actor.canAttentionPaw?[cmd('attentionPaw',[],'notifyPaw'),wait(.3,'notifyContact')]:[]),
|
|
247
|
+
cmd('look',[notice.side],'notify'),wait(2.5,'notify'),fx(()=>{notice=null;})];
|
|
242
248
|
}
|
|
243
249
|
// Run instant effects; stop at the first hold or issued command (at most one command per update).
|
|
244
250
|
for(;;){
|
|
@@ -311,14 +317,20 @@ export function createCompanionLife(actor,{seed=731,energy=.8,returnStyle='auto'
|
|
|
311
317
|
|
|
312
318
|
function clearNotice(){
|
|
313
319
|
if(!notice)return;
|
|
320
|
+
const approaching=notice.phase==='approaching';
|
|
314
321
|
notice=null;queue=[];hold=0;holdIntent=null;gesture=null;waiting=null;
|
|
322
|
+
intent='recover';label=LABEL.recover;
|
|
323
|
+
if(approaching||actor.state==='attention-paw'||actor.state==='attention-wall')actor.attend?.();
|
|
315
324
|
// Let any connected head turn/sit finish naturally. No snap or new route.
|
|
316
325
|
}
|
|
317
|
-
function notify({kind,side='left'}={}){
|
|
318
|
-
if(!['approval','input'].includes(kind)||!['left','right'].includes(side))throw Error('Invalid pet notice');
|
|
326
|
+
function notify({kind,side='left',gesture='auto'}={}){
|
|
327
|
+
if(!['approval','input'].includes(kind)||!['left','right'].includes(side)||!['auto','paw','wall'].includes(gesture))throw Error('Invalid pet notice');
|
|
319
328
|
// Explicit play/feeding always wins. Notifications never queue a second pet.
|
|
320
329
|
if(active||pending||notice)return false;
|
|
321
|
-
|
|
330
|
+
if(gesture==='wall'&&!actor.canAttentionWall)return false;
|
|
331
|
+
const selected=gesture==='auto'?(actor.canAttentionWall&¬iceCount%2===1?'wall':'paw'):gesture;
|
|
332
|
+
noticeCount++;
|
|
333
|
+
notice={kind,side,gesture:selected,phase:'queued'};
|
|
322
334
|
butterfly=null;queue=[];hold=0;holdIntent=null;gesture=null;waiting=null;
|
|
323
335
|
actor.attend?.();
|
|
324
336
|
return true;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// Generated by tools/bake-pet-motion.mjs. Do not edit by hand.
|
|
2
2
|
// Source paw labels are image-space proxies, not anatomical motion capture.
|
|
3
3
|
const freeze=v=>{if(v&&typeof v==='object'){for(const x of Object.values(v))freeze(x);Object.freeze(v);}return v;};
|
|
4
|
-
export const BAKED_MOTION=freeze({"version":1,"sources":{"puppy-stride-meta.json":"30fd474f3ed9337851b2071037d88d60b37cb2bb1c12d48b28c34ebc126b7e3a","puppy-paper-rear-gallop.json":"fe9b1bf0b88f2a366f28deee6cb63964b8a94d6faa99b111524112832e80705d","puppy-paper-approach.json":"e7e02589622cecde679de79bb79c71b77494fd2fd850793c2fba9754b46aa474","puppy-paper-actions-v9.json":"38b35496c552443c7ea99beceac3cd25c670bc91836b22509b1cc97da3d0a9de","puppy-paper-behaviors.json":"67d8633bc61a2d1c46206969b9aeaaf30073fcc0f0ae7dc9954957d5522edb32","puppy-companion-comfort.json":"5234cf9566957c91ad0aa76c5dae4c9449f6c34171dcb581bf6d114b607c4a18","puppy-paper-actions-v9-q5.bin.gz":"abb4677468206c62937c0247dc4c5823e0a7c4a3a197da40194a08dd594aeef9","puppy-paper-rear-gallop-q5.bin.gz":"ca731e1979a37ec2e005a80365e3b58358f640b8b26e7036b0e931940a7b1264","puppy-companion-comfort-q5.bin.gz":"9f8c89bf4764eb2f1f17131e2413d941f1eae33ae9a15ffbe76cc33f2d18103a","puppy-paper-arrival-seat-q5.bin.gz":"7effa0a2150e8ef9ed37d5b6cb10089672e0ce32599c06db21ad4769144bf246","puppy-paper-seat-q5.bin.gz":"5480c994de0d034d70eff6ea86095f3722cf87bde72f364dd369b94b1ad66f84","puppy-paper-behaviors-q5.bin.gz":"e4b79387aca974ceec74a02dc3f02780eb53d38af6ec9ebd69994de744b39716"},"support":{"front":{"step":16,"period":128,"cyclic":true,"offsets":{"0":0,"1":16,"2":32,"3":48,"4":64,"5":80,"6":96,"7":112},"starts":{"hind-near":[123,123,123,123,123,123,123,123,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,123,123,123,123,123],"fore-far":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],"fore-near":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],"hind-far":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]}},"rear":{"step":8,"period":64,"cyclic":true,"offsets":{"5":0,"6":8,"7":16,"8":24,"9":32,"10":40,"11":48,"12":56},"starts":{"hind-far":[60,60,60,60,60,60,60,60,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,60,60,60,60],"hind-near":[62,62,62,62,62,62,62,62,62,62,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,62]}},"approach":{"step":8,"period":64,"cyclic":true,"offsets":{"5":0,"6":8,"7":16,"8":24,"9":32,"10":40,"11":48,"12":56},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,39,39,39,39,39,39,-1,-1,-1,-1,-1,-1,-1,-1,-1,54,54,54,54,54,-1,-1,-1,-1,-1],"fore-right":[61,61,61,61,61,61,61,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,-1,-1,-1,-1,55,55,55,55,55,-1,61,61,61]}},"walk":{"step":8,"period":64,"cyclic":true,"offsets":{"42":0,"43":8,"44":16,"45":24,"46":32,"47":40,"48":48,"49":56},"starts":{"hind-far":[52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,52,52,52,52,52,52,52,52,52,52,52,52],"hind-near":[58,58,58,58,58,58,58,58,58,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,24,24,24,24,24,24,24,24,24,24,24,24,24,24,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,58,58,58,58,58,58],"fore-far":[-1,-1,-1,3,3,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,21,21,21,21,21,-1,-1,-1,-1,-1,31,31,31,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,47,47,47,47,47,-1,-1,-1,-1,-1,-1,-1,59,59,59,-1,-1],"fore-near":[-1,-1,-1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,-1,-1,-1,-1,-1,-1,-1,33,-1,-1,-1,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,-1,-1]}},"behavior/walk":{"step":8,"period":32,"cyclic":true,"offsets":{"0":0,"1":8,"2":16,"3":24},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,24,24,-1,-1,-1,-1,-1,-1],"fore-right":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]}},"behavior/walk-enter":{"step":8,"period":8,"cyclic":false,"offsets":{"4":0},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1],"fore-right":[-1,-1,-1,-1,4,4,4,4,4]}},"behavior/brake":{"step":8,"period":32,"cyclic":false,"offsets":{"5":0,"6":8,"7":16,"8":24},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1,9,9,9,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,23,23,23,23,23,23,23,23,23,23],"fore-right":[0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,15,15,15,15,15,15,15,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]}},"behavior/finish":{"step":8,"period":8,"cyclic":false,"offsets":{"9":0},"starts":{}},"behavior/watch-left":{"step":8,"period":16,"cyclic":false,"offsets":{"10":0,"11":8},"starts":{}},"behavior/watch-right":{"step":8,"period":16,"cyclic":false,"offsets":{"12":0,"13":8},"starts":{}},"behavior/rest":{"step":8,"period":32,"cyclic":false,"offsets":{"14":0,"15":8,"16":16,"17":24},"starts":{}}},"actionClips":{"spin":{"list":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],"weights":[1.1168,0.8052,0.827,0.7936,1.3421,1.4204,0.9015,0.5275,1.1081,0.7701,0.723,1.0494,1.4422,1.3325,1.0787,0.8964,0.8655],"total":17},"roll":{"list":[17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"weights":[1.122,1.4089,1.6479,0.6752,0.753,0.8756,0.9957,0.9586,0.7325,0.8218,1.0968,0.9962,0.8959,0.6589,1.0191,0.8352,0.4557,1.1818,1.1101,0.905,0.6752,1.6479,1.4089,1.122],"total":23.9999},"roll-down":{"list":[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"weights":[1.6886,0.6919,0.7717,0.8973,1.0203,0.9823,0.7506,0.8422,1.124,1.0208,0.918,0.6752,1.0443,0.8559,0.467,1.211,1.1376,0.9274,0.6919,1.6886,1.4438,1.1498],"total":22.0002},"lie-down":{"list":[17,18],"weights":[0.8866,1.1134],"total":2},"lie-up":{"list":[39,40],"weights":[1.1134,0.8866],"total":2},"walk-enter":{"list":[41],"weights":[1],"total":1},"walk":{"list":[42,43,44,45,46,47,48,49],"weights":[1,1,1,1,1,1,1,1],"total":8},"walk-exit":{"list":[50],"weights":[1],"total":1},"walk-face-front":{"list":[51],"weights":[1],"total":1},"walk-face-rear":{"list":[52],"weights":[1],"total":1},"walk-turn":{"list":[53,54,55,56,57,58,59,60,61,62,63,64,65],"weights":[1,1,1,1,1,1,1,1,1,1,1,1,1],"total":13}},"routes":{"maxPreparationSpeed":1e-8,"steps":[["ready"],["turn",true],["view-turn","rear"],["view-turn","approach"],["turn",false],["view-turn","front"],["rise"],["sit-down"]],"direction":[0,1,2,2,3,3,4,0,2,2,3,3,5,5,0,0,5,5,5,5,0,0,5,5,5,5,5,5,0,0,5,5,5,5,0,0],"action":[0,3,6,3,6,3,4,4,6,4,6,4,5,5,6,5,6,5,5,5,6,5,6,5,5,7,6,7,6,0,5,5,6,5,6,5]},"joins":{"walk-enter/walk":{"from":["puppy-paper-actions-v9",377],"to":["puppy-paper-actions-v9",378],"poseSha256":"81361614df56226b64be437f189c2e135c13498324286880db0fc06c5df3e86a","view":"front","speed":[0,0],"supportEvidence":"shared-pixels-with-labeled-walk-pose","supports":["hind-far","hind-near"],"phase":0},"walk/walk-exit":{"from":["puppy-paper-actions-v9",449],"to":["puppy-paper-actions-v9",450],"poseSha256":"81361614df56226b64be437f189c2e135c13498324286880db0fc06c5df3e86a","view":"front","speed":[0,0],"supportEvidence":"shared-pixels-with-labeled-walk-pose","supports":["hind-far","hind-near"],"phase":0},"rear-run/scramble":{"from":["puppy-paper-rear-gallop",63],"to":["puppy-companion-comfort",25],"poseSha256":"fa79a8762b57c0d5b70586a687f10e4a313e227e11e2435f6d7af0cd0866cc83","view":"rear","phase":0.25,"speed":[0,4.556913271064087],"positiveSpeed":true,"matchVelocity":true,"supports":[],"supportEvidence":"source-paw-proxies","airborne":true},"scramble/pickup-rear":{"from":["puppy-companion-comfort",36],"to":["puppy-companion-comfort",13],"poseSha256":"8192c504552a3984c80e1c3216e134605d4a930ec14cd7f778036e629e334601","view":"rear","speed":[0,0],"supports":["hind-far","hind-near"],"supportEvidence":"shared-pixels-with-labeled-rear-pose"},"carry-settle/arrival-seat":{"from":["puppy-companion-comfort",44],"to":["puppy-paper-arrival-seat",0],"poseSha256":"5ccf5acd9ca9ea81a0c9fc59d1ab2a2ddab148c942e31009f1a4c18de347fae8","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"tug/seat":{"from":["puppy-companion-comfort",0],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-90/seat":{"from":["puppy-paper-behaviors",90],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-107/seat":{"from":["puppy-paper-behaviors",107],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-108/seat":{"from":["puppy-paper-behaviors",108],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-125/seat":{"from":["puppy-paper-behaviors",125],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"}}});
|
|
4
|
+
export const BAKED_MOTION=freeze({"version":1,"sources":{"puppy-stride-meta.json":"30fd474f3ed9337851b2071037d88d60b37cb2bb1c12d48b28c34ebc126b7e3a","puppy-paper-rear-gallop.json":"fe9b1bf0b88f2a366f28deee6cb63964b8a94d6faa99b111524112832e80705d","puppy-paper-approach.json":"e7e02589622cecde679de79bb79c71b77494fd2fd850793c2fba9754b46aa474","puppy-paper-actions-v9.json":"38b35496c552443c7ea99beceac3cd25c670bc91836b22509b1cc97da3d0a9de","puppy-paper-behaviors.json":"67d8633bc61a2d1c46206969b9aeaaf30073fcc0f0ae7dc9954957d5522edb32","puppy-companion-comfort.json":"23ed137983ce5a653936a829932f41a16099378d7c0ad99b3f51a2e6091fc6bf","puppy-paper-actions-v9-q5.bin.gz":"abb4677468206c62937c0247dc4c5823e0a7c4a3a197da40194a08dd594aeef9","puppy-paper-rear-gallop-q5.bin.gz":"ca731e1979a37ec2e005a80365e3b58358f640b8b26e7036b0e931940a7b1264","puppy-companion-comfort-q5.bin.gz":"57942c55e9c467d973a08f1e23804b0f756eaed46dddfe3aba7e7c3621996236","puppy-paper-arrival-seat-q5.bin.gz":"7effa0a2150e8ef9ed37d5b6cb10089672e0ce32599c06db21ad4769144bf246","puppy-paper-seat-q5.bin.gz":"5480c994de0d034d70eff6ea86095f3722cf87bde72f364dd369b94b1ad66f84","puppy-paper-behaviors-q5.bin.gz":"e4b79387aca974ceec74a02dc3f02780eb53d38af6ec9ebd69994de744b39716"},"support":{"front":{"step":16,"period":128,"cyclic":true,"offsets":{"0":0,"1":16,"2":32,"3":48,"4":64,"5":80,"6":96,"7":112},"starts":{"hind-near":[123,123,123,123,123,123,123,123,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,123,123,123,123,123],"fore-far":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],"fore-near":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],"hind-far":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]}},"rear":{"step":8,"period":64,"cyclic":true,"offsets":{"5":0,"6":8,"7":16,"8":24,"9":32,"10":40,"11":48,"12":56},"starts":{"hind-far":[60,60,60,60,60,60,60,60,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,60,60,60,60],"hind-near":[62,62,62,62,62,62,62,62,62,62,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,62]}},"approach":{"step":8,"period":64,"cyclic":true,"offsets":{"5":0,"6":8,"7":16,"8":24,"9":32,"10":40,"11":48,"12":56},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,39,39,39,39,39,39,-1,-1,-1,-1,-1,-1,-1,-1,-1,54,54,54,54,54,-1,-1,-1,-1,-1],"fore-right":[61,61,61,61,61,61,61,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,-1,-1,-1,-1,55,55,55,55,55,-1,61,61,61]}},"walk":{"step":8,"period":64,"cyclic":true,"offsets":{"42":0,"43":8,"44":16,"45":24,"46":32,"47":40,"48":48,"49":56},"starts":{"hind-far":[52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,52,52,52,52,52,52,52,52,52,52,52,52],"hind-near":[58,58,58,58,58,58,58,58,58,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,24,24,24,24,24,24,24,24,24,24,24,24,24,24,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,58,58,58,58,58,58],"fore-far":[-1,-1,-1,3,3,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,21,21,21,21,21,-1,-1,-1,-1,-1,31,31,31,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,47,47,47,47,47,-1,-1,-1,-1,-1,-1,-1,59,59,59,-1,-1],"fore-near":[-1,-1,-1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,-1,-1,-1,-1,-1,-1,-1,33,-1,-1,-1,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,-1,-1]}},"behavior/walk":{"step":8,"period":32,"cyclic":true,"offsets":{"0":0,"1":8,"2":16,"3":24},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,24,24,-1,-1,-1,-1,-1,-1],"fore-right":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]}},"behavior/walk-enter":{"step":8,"period":8,"cyclic":false,"offsets":{"4":0},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1],"fore-right":[-1,-1,-1,-1,4,4,4,4,4]}},"behavior/brake":{"step":8,"period":32,"cyclic":false,"offsets":{"5":0,"6":8,"7":16,"8":24},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1,9,9,9,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,23,23,23,23,23,23,23,23,23,23],"fore-right":[0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,15,15,15,15,15,15,15,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]}},"behavior/finish":{"step":8,"period":8,"cyclic":false,"offsets":{"9":0},"starts":{}},"behavior/watch-left":{"step":8,"period":16,"cyclic":false,"offsets":{"10":0,"11":8},"starts":{}},"behavior/watch-right":{"step":8,"period":16,"cyclic":false,"offsets":{"12":0,"13":8},"starts":{}},"behavior/rest":{"step":8,"period":32,"cyclic":false,"offsets":{"14":0,"15":8,"16":16,"17":24},"starts":{}}},"actionClips":{"spin":{"list":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],"weights":[1.1168,0.8052,0.827,0.7936,1.3421,1.4204,0.9015,0.5275,1.1081,0.7701,0.723,1.0494,1.4422,1.3325,1.0787,0.8964,0.8655],"total":17},"roll":{"list":[17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"weights":[1.122,1.4089,1.6479,0.6752,0.753,0.8756,0.9957,0.9586,0.7325,0.8218,1.0968,0.9962,0.8959,0.6589,1.0191,0.8352,0.4557,1.1818,1.1101,0.905,0.6752,1.6479,1.4089,1.122],"total":23.9999},"roll-down":{"list":[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"weights":[1.6886,0.6919,0.7717,0.8973,1.0203,0.9823,0.7506,0.8422,1.124,1.0208,0.918,0.6752,1.0443,0.8559,0.467,1.211,1.1376,0.9274,0.6919,1.6886,1.4438,1.1498],"total":22.0002},"lie-down":{"list":[17,18],"weights":[0.8866,1.1134],"total":2},"lie-up":{"list":[39,40],"weights":[1.1134,0.8866],"total":2},"walk-enter":{"list":[41],"weights":[1],"total":1},"walk":{"list":[42,43,44,45,46,47,48,49],"weights":[1,1,1,1,1,1,1,1],"total":8},"walk-exit":{"list":[50],"weights":[1],"total":1},"walk-face-front":{"list":[51],"weights":[1],"total":1},"walk-face-rear":{"list":[52],"weights":[1],"total":1},"walk-turn":{"list":[53,54,55,56,57,58,59,60,61,62,63,64,65],"weights":[1,1,1,1,1,1,1,1,1,1,1,1,1],"total":13}},"routes":{"maxPreparationSpeed":1e-8,"steps":[["ready"],["turn",true],["view-turn","rear"],["view-turn","approach"],["turn",false],["view-turn","front"],["rise"],["sit-down"]],"direction":[0,1,2,2,3,3,4,0,2,2,3,3,5,5,0,0,5,5,5,5,0,0,5,5,5,5,5,5,0,0,5,5,5,5,0,0],"action":[0,3,6,3,6,3,4,4,6,4,6,4,5,5,6,5,6,5,5,5,6,5,6,5,5,7,6,7,6,0,5,5,6,5,6,5]},"joins":{"walk-enter/walk":{"from":["puppy-paper-actions-v9",377],"to":["puppy-paper-actions-v9",378],"poseSha256":"81361614df56226b64be437f189c2e135c13498324286880db0fc06c5df3e86a","view":"front","speed":[0,0],"supportEvidence":"shared-pixels-with-labeled-walk-pose","supports":["hind-far","hind-near"],"phase":0},"walk/walk-exit":{"from":["puppy-paper-actions-v9",449],"to":["puppy-paper-actions-v9",450],"poseSha256":"81361614df56226b64be437f189c2e135c13498324286880db0fc06c5df3e86a","view":"front","speed":[0,0],"supportEvidence":"shared-pixels-with-labeled-walk-pose","supports":["hind-far","hind-near"],"phase":0},"rear-run/scramble":{"from":["puppy-paper-rear-gallop",63],"to":["puppy-companion-comfort",25],"poseSha256":"fa79a8762b57c0d5b70586a687f10e4a313e227e11e2435f6d7af0cd0866cc83","view":"rear","phase":0.25,"speed":[0,4.556913271064087],"positiveSpeed":true,"matchVelocity":true,"supports":[],"supportEvidence":"source-paw-proxies","airborne":true},"scramble/pickup-rear":{"from":["puppy-companion-comfort",36],"to":["puppy-companion-comfort",13],"poseSha256":"8192c504552a3984c80e1c3216e134605d4a930ec14cd7f778036e629e334601","view":"rear","speed":[0,0],"supports":["hind-far","hind-near"],"supportEvidence":"shared-pixels-with-labeled-rear-pose"},"carry-settle/arrival-seat":{"from":["puppy-companion-comfort",44],"to":["puppy-paper-arrival-seat",0],"poseSha256":"5ccf5acd9ca9ea81a0c9fc59d1ab2a2ddab148c942e31009f1a4c18de347fae8","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"tug/seat":{"from":["puppy-companion-comfort",0],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-90/seat":{"from":["puppy-paper-behaviors",90],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-107/seat":{"from":["puppy-paper-behaviors",107],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-108/seat":{"from":["puppy-paper-behaviors",108],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-125/seat":{"from":["puppy-paper-behaviors",125],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"}}});
|
package/puppy-paper.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import {createPaperAreaSampler} from './puppy-paper-area.mjs';
|
|
|
9
9
|
import {PAPER_ACTION_DURATIONS,createPaperActionSampler,paperActionPose} from './puppy-paper-actions.mjs';
|
|
10
10
|
import {createPawTransport} from './puppy-paper-paw-transport.mjs';
|
|
11
11
|
import {createCompanionSpriteSampler} from './puppy-companion-sprites.mjs';
|
|
12
|
-
import {createComfortSpriteSampler,comfortMotion,comfortMotionKey} from './puppy-comfort-sprites.mjs';
|
|
12
|
+
import {createComfortSpriteSampler,comfortMotion,comfortMotionKey,comfortProgress} from './puppy-comfort-sprites.mjs';
|
|
13
13
|
import {mouthSourceFrame,mouthAnchor,projectMouth} from './puppy-mouth-anchor.mjs';
|
|
14
14
|
import {trickClipEdges} from './puppy-paper-trick-timing.mjs';
|
|
15
15
|
|
|
@@ -70,7 +70,7 @@ export function createPaperActor(animal,info,{manualTricks=false,trickTimings=nu
|
|
|
70
70
|
const launchSeconds=()=>snappyPreparation()?.10:.25;
|
|
71
71
|
const dispatch=(fn,{keepDown=false,urgent=false}={})=>{
|
|
72
72
|
if(urgent)preparationRate=3;
|
|
73
|
-
if(activeAction||state==='tug'||state==='scramble'||state==='pickup'||(movementMode==='walk'&&state==='run')){route=false;deferred=()=>dispatch(fn,{keepDown,urgent});hurryComfort();return true;}
|
|
73
|
+
if(activeAction||state==='tug'||state==='attention-paw'||state==='attention-wall'||state==='scramble'||state==='pickup'||(movementMode==='walk'&&state==='run')){route=false;deferred=()=>dispatch(fn,{keepDown,urgent});hurryComfort();return true;}
|
|
74
74
|
// The calibrated trick down pose has its own byte-shared recovery; never
|
|
75
75
|
// jump back into the older/larger rest illustration on another command.
|
|
76
76
|
if(manualDown&&!keepDown){route=false;deferred=fn;playAction('lie-up',()=>{manualDown=false;view='approach';seatProgress=1;seatVariant='default';enter('idle');drain();},.55);return true;}
|
|
@@ -94,6 +94,7 @@ export function createPaperActor(animal,info,{manualTricks=false,trickTimings=nu
|
|
|
94
94
|
const t=activeAction?.timing;
|
|
95
95
|
if(t?.comfort==='belly'&&age<t.hold[1]){t.hold[1]=Math.max(t.hold[0],age);t.duration=activeAction.duration=t.hold[1]+bellyTiming.exit;}
|
|
96
96
|
else if(state==='tug'&&comfort&&!comfort.hurry){const progress=tugProgress();comfort.hurry={progress,age,length:Math.min(comfortTimings.tugExit,(1-progress)*comfort.seconds)};}
|
|
97
|
+
else if((state==='attention-paw'||state==='attention-wall')&&comfort&&!comfort.hurry){const motion=state==='attention-wall'?fetchMotions.attentionWall:fetchMotions.attentionPaw,progress=held?.comfortPose?.clip===state?held.comfortPose.progress:Math.min(1,age/comfort.seconds),from=motion.frames[comfortMotionKey(progress,motion)];comfort.hurry={from,age,length:motion.releases[from].duration};}
|
|
97
98
|
}
|
|
98
99
|
const playAction=(name,done,duration=PAPER_ACTION_DURATIONS[name])=>{const timing=trickTimings?.[name];duration=timing?.duration??duration;if(!Number.isFinite(duration)||duration<=0)throw Error('Invalid paper action duration');activeAction={name,duration,timing};actionDone=done;stop();enter('action');};
|
|
99
100
|
const finishTrick=name=>{if(name!=='spin'){view='approach';flip=false;seatProgress=1;seatVariant='default';enter('idle');}else{view='front';flip=false;seatProgress=0;enter('settle');}drain();};
|
|
@@ -143,6 +144,7 @@ export function createPaperActor(animal,info,{manualTricks=false,trickTimings=nu
|
|
|
143
144
|
if(name==='belly'){const seconds=comfortSeconds;playAction('lie-down',()=>startBelly(seconds),.65);return;}
|
|
144
145
|
if(name==='sleep'){stayDown=false;sleepLook={...nextSleepLook};comfort={kind:'sleep',seconds:comfortSeconds};enter('recline');return;}
|
|
145
146
|
if(name==='tug'){stop();comfort={kind:'tug',seconds:comfortSeconds};enter('tug');return;}
|
|
147
|
+
if(name==='attention-paw'||name==='attention-wall'){stop();held=null;comfort={kind:name,seconds:(name==='attention-wall'?fetchMotions.attentionWall:fetchMotions.attentionPaw).duration};enter(name);return;}
|
|
146
148
|
if(name==='lie'){
|
|
147
149
|
if(manualTricks){playAction('lie-down',()=>{manualDown=true;enter('down');drain();},.65);}
|
|
148
150
|
else{stayDown=true;enter('recline');}
|
|
@@ -228,6 +230,10 @@ export function createPaperActor(animal,info,{manualTricks=false,trickTimings=nu
|
|
|
228
230
|
belly(seconds=6){comfortDuration('belly',seconds);return dispatch(()=>{comfortSeconds=seconds;return requestAction('belly');},{keepDown:true});},
|
|
229
231
|
sleep(seconds=25,variant='side',right=false){comfortDuration('sleep',seconds);if(!['side','belly','curl','chin'].includes(variant)||typeof right!=='boolean')throw Error('Invalid sleep pose');return dispatch(()=>{comfortSeconds=seconds;nextSleepLook={variant,right};return requestAction('sleep');});},
|
|
230
232
|
tug(seconds=6){comfortDuration('tug',seconds);return dispatch(()=>{comfortSeconds=seconds;return requestAction('tug');});},
|
|
233
|
+
attentionPaw(){if(!fetchMotions?.attentionPaw)return false;return dispatch(()=>requestAction('attention-paw'));},
|
|
234
|
+
get canAttentionPaw(){return !!fetchMotions?.attentionPaw;},
|
|
235
|
+
attentionWall(){if(!fetchMotions?.attentionWall)return false;return dispatch(()=>requestAction('attention-wall'));},
|
|
236
|
+
get canAttentionWall(){return !!fetchMotions?.attentionWall;},
|
|
231
237
|
get canScramble(){return scrambleSeconds>0;},
|
|
232
238
|
get canMovingScramble(){return !!fetchMotions;},
|
|
233
239
|
get canSinglePassScramble(){return fetchMotions?.scramble.trajectory==='single-pass-target';},
|
|
@@ -292,6 +298,7 @@ export function createPaperActor(animal,info,{manualTricks=false,trickTimings=nu
|
|
|
292
298
|
else if(state==='recline'){const end=stayDown?.25:1;restProgress=Math.min(end,restProgress+dt/1.8);if(restProgress===end)enter(stayDown?'down':comfort?.kind==='sleep'?'sleep':'nap');}
|
|
293
299
|
else if(state==='sleep'&&age>=comfort.seconds){comfort=null;enter('wake');}
|
|
294
300
|
else if(state==='tug'&&tugProgress()>=1){comfort=null;enter('idle');drain();}
|
|
301
|
+
else if((state==='attention-paw'||state==='attention-wall')&&(comfort.hurry?age-comfort.hurry.age>=comfort.hurry.length:age>=comfort.seconds)){comfort=null;enter('idle');drain();}
|
|
295
302
|
else if((state==='scramble'||state==='pickup')&&age>=comfort.seconds){comfort=null;movingScramble=null;stop();enter('idle');drain();}
|
|
296
303
|
else if(state==='nap'&&age>=5&&!stayDown){enter('wake');}
|
|
297
304
|
else if(state==='wake'){restProgress=Math.max(0,restProgress-prepareDt/1.2);if(restProgress===0){if(pendingAction)prepareDirection();else if(target)enter('rise');else enter('idle');}}
|
|
@@ -304,6 +311,7 @@ export function createPaperActor(animal,info,{manualTricks=false,trickTimings=nu
|
|
|
304
311
|
let seat=state==='sit-down'||state==='rise'||seatProgress>0?Math.round(seatProgress*48)/48:null;
|
|
305
312
|
if(restProgress===0&&state!=='recline')sleepLook=null;
|
|
306
313
|
let behavior=null,behaviorProgress=0,comfortPose=state==='scramble'?{clip:'scramble',view,progress:Math.min(1,age/comfort.seconds)}:state==='pickup'?{clip:'pickup',view,progress:Math.min(1,age/comfort.seconds)}:state==='tug'?{clip:'tug',progress:tugProgress()}:sleepLook&&restProgress>.72?{clip:'sleep',...sleepLook,blend:comfortEase((restProgress-.72)/.28)}:null;
|
|
314
|
+
if(state==='attention-paw'||state==='attention-wall')comfortPose={clip:state,progress:Math.min(1,age/comfort.seconds),...comfort.hurry?{release:{from:comfort.hurry.from,progress:Math.min(1,(age-comfort.hurry.age)/comfort.hurry.length)}}:{}};
|
|
307
315
|
if(activeAction?.comfort)kind=activeAction.comfort;
|
|
308
316
|
let actionName=activeAction?.name??(state==='run'&&movementMode==='walk'?'walk':null),actionProgress=activeAction?(activeAction.timing?activeAction.timing.progressAt(age):Math.min(1,age/activeAction.duration)):phase;
|
|
309
317
|
if(manualDown&&state==='down'){actionName='lie-down';actionProgress=1;}
|
|
@@ -386,7 +394,7 @@ export function createPaperRenderer(cache,info,meta,width,height,{rear,approach,
|
|
|
386
394
|
// Quantize source lookup only, never the projected rectangle. Rounding side,
|
|
387
395
|
// left and top first introduced whole-body scale/position jumps at thresholds.
|
|
388
396
|
const motion=isComfort?comfortMotion(state.comfortPose,comfort.info):null;
|
|
389
|
-
const left=width*x-sideX/2,floor=motion?(motion.floorOffsets?.[comfortMotionKey(state.comfortPose
|
|
397
|
+
const left=width*x-sideX/2,floor=motion?(motion.floorOffsets?.[comfortMotionKey(comfortProgress(state.comfortPose),motion)]??motion.floorOffset??0):isInteraction||isAction||isBehavior||isSeat||isRear||isApproach?0:cleanGroundOffset(state,renderMeta),top=height*y-(300-floor)/320*side;
|
|
390
398
|
let feet=[];
|
|
391
399
|
if(contactEnabled&&isComfort&&state.comfortPose.clip==='carry-trot'){
|
|
392
400
|
const k=comfortMotionKey(state.comfortPose.progress,motion);
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
export interface AttentionSnapshot {
|
|
2
2
|
source: string;
|
|
3
3
|
scope: string;
|
|
4
|
-
|
|
4
|
+
/** label is a bounded local display name, never remote model input. */
|
|
5
|
+
items: {id: string; generation: string; turnId: number | null; requestId?: string; kind: 'approval' | 'input'; label?: string}[];
|
|
5
6
|
}
|
|
6
7
|
export interface AttentionStatus {
|
|
7
8
|
state: 'connecting' | 'connected' | 'unavailable' | 'paused' | 'stale' | 'off';
|
|
8
9
|
pendingCount: number;
|
|
10
|
+
target: {seatId: string; label: string; kind: 'approval' | 'input'} | null;
|
|
9
11
|
retainedNotices: number;
|
|
10
12
|
inFlight: boolean;
|
|
11
13
|
judging?: boolean;
|
|
12
|
-
lastJudgment?: 'model_notify' | 'rule_override' | 'rule_fallback' | null;
|
|
14
|
+
lastJudgment?: 'rule_first' | 'model_notify' | 'rule_override' | 'rule_fallback' | null;
|
|
13
15
|
}
|
|
14
16
|
export function validateAttentionSnapshot(value: unknown): AttentionSnapshot;
|
|
15
17
|
/** Host owns tick/lifetime. Import and construction start no timers or I/O. */
|
|
@@ -18,7 +20,7 @@ export function createAttentionMonitor(options: {
|
|
|
18
20
|
onNotice: (notice: {kind: 'approval' | 'input'; side: 'left'}) => boolean;
|
|
19
21
|
onClear?: () => void;
|
|
20
22
|
onChange?: (status: AttentionStatus) => void;
|
|
21
|
-
/** Anonymous metadata only.
|
|
23
|
+
/** Anonymous metadata only. Runs after the immediate rule alert, never delays or suppresses it. */
|
|
22
24
|
judgeNotice?: (input: {kind: 'approval' | 'input'; pendingCount: number; signal: AbortSignal}) => Promise<{decision: 'notify' | 'ignore' | 'uncertain'}>;
|
|
23
25
|
judgeTimeoutMs?: number;
|
|
24
26
|
now?: () => number;
|
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
// Screen/app text is data, never an instruction or an executable action.
|
|
3
3
|
const MAX_ITEMS=32,MAX_SEEN=128;
|
|
4
4
|
const bounded=(value,max=128)=>typeof value==='string'&&value.length>0&&value.length<=max&&!/[\x00-\x1f\x7f]/.test(value);
|
|
5
|
+
// Cosmetic, local-only metadata. Never let a malformed title hide a real alert.
|
|
6
|
+
const localLabel=value=>typeof value==='string'?value.slice(0,256).replace(/[\x00-\x1f\x7f-\x9f\u200b-\u200f\u202a-\u202e\u2060-\u206f]/g,'').replace(/\s+/g,' ').trim().slice(0,64).replace(/[\ud800-\udbff]$/,'')||undefined:undefined;
|
|
5
7
|
export function validateAttentionSnapshot(value){
|
|
6
8
|
if(!value||!bounded(value.source,32)||!bounded(value.scope,256)||!Array.isArray(value.items)||value.items.length>MAX_ITEMS)throw Error('Invalid attention snapshot');
|
|
7
9
|
const identities=new Set();
|
|
8
10
|
const items=value.items.map(item=>{
|
|
9
11
|
if(!item||!bounded(item.id)||!bounded(item.generation)||!(item.turnId===null||Number.isSafeInteger(item.turnId)&&item.turnId>=1)||item.requestId!==undefined&&!bounded(item.requestId)||item.turnId===null&&item.requestId===undefined||!['approval','input'].includes(item.kind))throw Error('Invalid attention item');
|
|
10
12
|
const key=JSON.stringify([item.id,item.generation,item.turnId,item.requestId??null]);if(identities.has(key))throw Error('Duplicate attention item');identities.add(key);
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
+
// No arbitrary source fields, output text, prompts, paths or tokens. A Seat's
|
|
14
|
+
// bounded display label is for local status only, never the remote judge.
|
|
15
|
+
const label=localLabel(item.label);
|
|
16
|
+
return {id:item.id,generation:item.generation,turnId:item.turnId,...item.requestId===undefined?{}:{requestId:item.requestId},kind:item.kind,...label?{label}:{}};
|
|
13
17
|
});
|
|
14
18
|
return {source:value.source,scope:value.scope,items};
|
|
15
19
|
}
|
|
@@ -19,14 +23,19 @@ export function createAttentionMonitor({readSnapshot,onNotice,onClear=()=>{},onC
|
|
|
19
23
|
if(judgeNotice!==undefined&&typeof judgeNotice!=='function')throw TypeError('judgeNotice must be a function');
|
|
20
24
|
if(!Number.isFinite(judgeTimeoutMs)||judgeTimeoutMs<100||judgeTimeoutMs>15000)throw RangeError('Invalid judge timeout');
|
|
21
25
|
if(!Number.isFinite(intervalMs)||intervalMs<1000||intervalMs>60000||!Number.isFinite(staleMs)||staleMs<intervalMs*2||staleMs>300000||!Number.isFinite(noticeCooldownMs)||noticeCooldownMs<1000||noticeCooldownMs>300000)throw RangeError('Invalid attention timing');
|
|
22
|
-
let disposed=false,paused=false,flight=null,nextRead=0,nextNotice=0,lastSuccess=null,snapshot=null,state='connecting',lastReport='',cueKey=null,judgment=null,lastJudgment=null;
|
|
26
|
+
let disposed=false,paused=false,flight=null,nextRead=0,nextNotice=0,lastSuccess=null,snapshot=null,state='connecting',lastReport='',cueKey=null,judgment=null,lastJudgment=null,target=null,targetKey='';
|
|
23
27
|
const seen=new Map();
|
|
24
28
|
const identity=(value,item)=>JSON.stringify([value.source,value.scope,item.id,item.generation,item.turnId,item.requestId??null]);
|
|
25
|
-
const
|
|
29
|
+
const refreshTarget=()=>{
|
|
30
|
+
const item=snapshot?.items.find(row=>identity(snapshot,row)===cueKey)??snapshot?.items.find(row=>row.kind==='approval')??snapshot?.items[0];
|
|
31
|
+
target=item?{seatId:item.id,label:item.label??(item.id.length<=32?item.id:'Seat '+item.id.slice(-8)),kind:item.kind}:null;
|
|
32
|
+
targetKey=JSON.stringify(target);
|
|
33
|
+
};
|
|
34
|
+
const clearCue=()=>{if(cueKey!==null){cueKey=null;refreshTarget();onClear();}};
|
|
26
35
|
const cancelJudgment=()=>{const old=judgment;judgment=null;old?.controller.abort();};
|
|
27
|
-
const report=()=>({state,pendingCount:snapshot?.items.length??0,retainedNotices:seen.size,inFlight:flight!==null,...judgeNotice?{judging:!!judgment&&!judgment.ready,lastJudgment}:{}});
|
|
28
|
-
const changed=()=>{const key=state+'|'+(snapshot?.items.length??0);if(key!==lastReport){lastReport=key;onChange(report());}};
|
|
29
|
-
const clear=next=>{snapshot=null;lastSuccess=null;state=next;cancelJudgment();clearCue();changed();};
|
|
36
|
+
const report=()=>({state,pendingCount:snapshot?.items.length??0,target:target?{...target}:null,retainedNotices:seen.size,inFlight:flight!==null,...judgeNotice?{judging:!!judgment&&!judgment.ready,lastJudgment}:{}});
|
|
37
|
+
const changed=()=>{const key=state+'|'+(snapshot?.items.length??0)+'|'+targetKey+'|'+!!judgment+'|'+lastJudgment;if(key!==lastReport){lastReport=key;onChange(report());}};
|
|
38
|
+
const clear=next=>{snapshot=null;refreshTarget();lastSuccess=null;state=next;cancelJudgment();clearCue();changed();};
|
|
30
39
|
function startRead(t){
|
|
31
40
|
const operation={controller:new AbortController()};flight=operation;nextRead=t+intervalMs;
|
|
32
41
|
operation.done=(async()=>{
|
|
@@ -38,6 +47,7 @@ export function createAttentionMonitor({readSnapshot,onNotice,onClear=()=>{},onC
|
|
|
38
47
|
snapshot=result;lastSuccess=now();state='connected';
|
|
39
48
|
if(cueKey!==null&&!snapshot.items.some(item=>identity(snapshot,item)===cueKey))clearCue();
|
|
40
49
|
if(judgment&&!snapshot.items.some(item=>identity(snapshot,item)===judgment.key))cancelJudgment();
|
|
50
|
+
refreshTarget();
|
|
41
51
|
}catch{
|
|
42
52
|
if(disposed||paused||flight!==operation)return;
|
|
43
53
|
// No source stderr, credentials, or stale pending facts escape on failure.
|
|
@@ -58,35 +68,33 @@ export function createAttentionMonitor({readSnapshot,onNotice,onClear=()=>{},onC
|
|
|
58
68
|
if(paused){paused=false;nextRead=t;state='connecting';changed();}
|
|
59
69
|
if(snapshot&&t-lastSuccess>=staleMs)clear('stale');
|
|
60
70
|
if(!flight&&t>=nextRead)startRead(t);
|
|
71
|
+
// Advice settles independently of alert delivery. It cannot delay, retract,
|
|
72
|
+
// repeat, or move an already-confirmed human-input notification.
|
|
73
|
+
if(judgment){
|
|
74
|
+
if(!judgment.ready&&t-judgment.start>=judgeTimeoutMs){judgment.ready=true;judgment.decision='uncertain';judgment.controller.abort();}
|
|
75
|
+
if(judgment.ready){lastJudgment=judgment.decision==='notify'?'model_notify':judgment.decision==='ignore'?'rule_override':'rule_fallback';judgment=null;}
|
|
76
|
+
}
|
|
61
77
|
// A refresh already in flight may resolve/replace the candidate. Do not emit
|
|
62
78
|
// an old cue in the microtask gap just before that fresh snapshot arrives.
|
|
63
79
|
if(!flight&&snapshot&&state==='connected'&&t<lastSuccess+staleMs&&t>=nextNotice){
|
|
64
80
|
// Approval and generic input for the same exact turn are one notification.
|
|
65
81
|
let item=null;
|
|
66
82
|
for(const row of snapshot.items)if(!seen.has(identity(snapshot,row))){if(!item)item=row;if(row.kind==='approval'){item=row;break;}}
|
|
67
|
-
if(item&&
|
|
68
|
-
const key=identity(snapshot,item);
|
|
69
|
-
|
|
70
|
-
|
|
83
|
+
if(item&&onNotice({kind:item.kind,side:'left'})===true){
|
|
84
|
+
const key=identity(snapshot,item);seen.set(key,true);cueKey=key;
|
|
85
|
+
refreshTarget();
|
|
86
|
+
if(judgeNotice){
|
|
87
|
+
cancelJudgment();lastJudgment='rule_first';
|
|
88
|
+
const operation={key,controller:new AbortController(),ready:false,start:t};judgment=operation;
|
|
71
89
|
const facts={kind:item.kind,pendingCount:snapshot.items.length,signal:operation.controller.signal};
|
|
72
|
-
// Only anonymous enums/counts leave the coordinator; identities stay local.
|
|
73
90
|
operation.done=Promise.resolve().then(()=>{if(operation.controller.signal.aborted)throw Error('Canceled judgment');return judgeNotice(facts);}).then(result=>{
|
|
74
91
|
if(judgment===operation&&!disposed&&!paused&&!operation.controller.signal.aborted){operation.decision=['notify','ignore','uncertain'].includes(result?.decision)?result.decision:'uncertain';operation.ready=true;}
|
|
75
92
|
},()=>{if(judgment===operation&&!disposed&&!paused){operation.decision='uncertain';operation.ready=true;}});
|
|
76
93
|
}
|
|
77
|
-
if(!judgment.ready&&t-judgment.start>=judgeTimeoutMs){judgment.ready=true;judgment.decision='uncertain';judgment.controller.abort();}
|
|
78
|
-
if(!judgment.ready){changed();return;}
|
|
79
|
-
// These are confirmed pending human-input facts, not speculative screen
|
|
80
|
-
// guesses. A model may advise, but may never hide them or authorize input.
|
|
81
|
-
}
|
|
82
|
-
if(item&&onNotice({kind:item.kind,side:'left'})===true){
|
|
83
|
-
if(judgment)lastJudgment=judgment.decision==='notify'?'model_notify':judgment.decision==='ignore'?'rule_override':'rule_fallback';
|
|
84
|
-
const key=identity(snapshot,item);seen.set(key,true);cueKey=key;
|
|
85
94
|
// Still-pending identities cannot be evicted into repeated notifications.
|
|
86
95
|
const live=new Set(snapshot.items.map(row=>identity(snapshot,row)));
|
|
87
96
|
for(const prior of seen.keys()){if(seen.size<=MAX_SEEN)break;if(!live.has(prior))seen.delete(prior);}
|
|
88
97
|
nextNotice=t+noticeCooldownMs;
|
|
89
|
-
cancelJudgment();
|
|
90
98
|
}
|
|
91
99
|
}
|
|
92
100
|
changed();
|
|
@@ -94,6 +102,6 @@ export function createAttentionMonitor({readSnapshot,onNotice,onClear=()=>{},onC
|
|
|
94
102
|
get status(){return report();},
|
|
95
103
|
// For host shutdown/verification, not a second polling loop.
|
|
96
104
|
async settled(){await flight?.done;await judgment?.done;},
|
|
97
|
-
dispose(){if(disposed)return;disposed=true;const old=flight;flight=null;old?.controller.abort();cancelJudgment();clearCue();
|
|
105
|
+
dispose(){if(disposed)return;disposed=true;const old=flight;flight=null;old?.controller.abort();cancelJudgment();snapshot=null;refreshTarget();clearCue();seen.clear();state='off';},
|
|
98
106
|
};
|
|
99
107
|
}
|
package/retrieviewer.d.mts
CHANGED
|
@@ -41,7 +41,7 @@ export interface PetState {
|
|
|
41
41
|
}
|
|
42
42
|
export interface LifeReport {
|
|
43
43
|
/** Metadata-triggered visual cue only. No host input or approval authority. */
|
|
44
|
-
attention: {kind: 'approval' | 'input'; side: 'left' | 'right'; phase: 'queued' | 'showing'} | null;
|
|
44
|
+
attention: {kind: 'approval' | 'input'; side: 'left' | 'right'; gesture: 'paw' | 'wall'; phase: 'queued' | 'approaching' | 'showing'} | null;
|
|
45
45
|
/** Last selected autonomous episode; null before the first decision. */
|
|
46
46
|
episode: string | null;
|
|
47
47
|
intent: string;
|
|
@@ -96,7 +96,7 @@ export interface Pet {
|
|
|
96
96
|
/** False when busy or cooling down. */
|
|
97
97
|
interact(kind: 'ball' | 'treat' | 'tug'): boolean;
|
|
98
98
|
/** False during direct play/feeding or another cue. Does not operate the host. */
|
|
99
|
-
notify(notice: {kind: 'approval' | 'input'; side?: 'left' | 'right'}): boolean;
|
|
99
|
+
notify(notice: {kind: 'approval' | 'input'; side?: 'left' | 'right'; gesture?: 'auto' | 'paw' | 'wall'}): boolean;
|
|
100
100
|
/** Cancel the cue, preserving any in-progress connected pose recovery. */
|
|
101
101
|
clearNotice(): void;
|
|
102
102
|
/** Sets the next throw's return style. Does not interrupt a fetch in progress. */
|