@bitefoundry/retrieviewer 0.0.15 → 0.0.17

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.
Files changed (41) hide show
  1. package/ASSET-PROVENANCE.md +13 -0
  2. package/ATTENTION-PAW.md +53 -0
  3. package/ATTENTION-WALL.md +58 -0
  4. package/ATTENTION.md +12 -1
  5. package/EMBEDDING.md +15 -9
  6. package/PUPPY-MEMORY.md +59 -0
  7. package/README.ko.md +7 -0
  8. package/README.md +8 -0
  9. package/RELEASING.md +34 -1
  10. package/integrations/stackbite/attention.mjs +20 -3
  11. package/package.json +19 -12
  12. package/pet-indexed-manifest.json +106 -0
  13. package/puppy-comfort-sprites.mjs +10 -4
  14. package/puppy-companion-comfort-q5.rvz +0 -0
  15. package/puppy-companion-comfort.json +818 -5
  16. package/puppy-companion-interactions-v3-q5.rvz +0 -0
  17. package/puppy-companion-life.mjs +11 -6
  18. package/puppy-frame-file.mjs +15 -0
  19. package/puppy-frame-indexed.mjs +78 -0
  20. package/puppy-frame-predictive.mjs +1 -1
  21. package/puppy-frame-store.mjs +6 -0
  22. package/puppy-motion-tables.generated.mjs +1 -1
  23. package/puppy-paper-actions-v9-q5.rvz +0 -0
  24. package/puppy-paper-approach-q5.rvz +0 -0
  25. package/puppy-paper-arrival-seat-q5.rvz +0 -0
  26. package/puppy-paper-behaviors-q5.rvz +0 -0
  27. package/puppy-paper-rear-gallop-q5.rvz +0 -0
  28. package/puppy-paper-seat-q5.rvz +0 -0
  29. package/puppy-paper.mjs +11 -3
  30. package/puppy-stride-tweens-q5.rvz +0 -0
  31. package/retrieviewer.d.mts +3 -3
  32. package/retrieviewer.mjs +22 -10
  33. package/puppy-companion-comfort-q5.bin.gz +0 -0
  34. package/puppy-companion-interactions-v3-q5.bin.gz +0 -0
  35. package/puppy-paper-actions-v9-q5.bin.gz +0 -0
  36. package/puppy-paper-approach-q5.bin.gz +0 -0
  37. package/puppy-paper-arrival-seat-q5.bin.gz +0 -0
  38. package/puppy-paper-behaviors-q5.bin.gz +0 -0
  39. package/puppy-paper-rear-gallop-q5.bin.gz +0 -0
  40. package/puppy-paper-seat-q5.bin.gz +0 -0
  41. package/puppy-stride-tweens-q5.bin.gz +0 -0
@@ -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:'확인할 일을 발견하고 앉는 중',notifyContact:'확인할 일이 있어 사용자를 바라보는 중',notifyCome:'확인할 일을 알려주러 가까이 오는 중',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]});
@@ -242,6 +243,7 @@ export function createCompanionLife(actor,{seed=731,energy=.8,returnStyle='auto'
242
243
  queue=[sit('notifySit'),wait(.45,'notifyContact'),
243
244
  fx(()=>{if(far())notice.phase='approaching';}),cmd('go',[HOME.x,HOME.z],'notifyCome',far),
244
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')]:[]),
245
247
  cmd('look',[notice.side],'notify'),wait(2.5,'notify'),fx(()=>{notice=null;})];
246
248
  }
247
249
  // Run instant effects; stop at the first hold or issued command (at most one command per update).
@@ -318,14 +320,17 @@ export function createCompanionLife(actor,{seed=731,energy=.8,returnStyle='auto'
318
320
  const approaching=notice.phase==='approaching';
319
321
  notice=null;queue=[];hold=0;holdIntent=null;gesture=null;waiting=null;
320
322
  intent='recover';label=LABEL.recover;
321
- if(approaching)actor.attend?.();
323
+ if(approaching||actor.state==='attention-paw'||actor.state==='attention-wall')actor.attend?.();
322
324
  // Let any connected head turn/sit finish naturally. No snap or new route.
323
325
  }
324
- function notify({kind,side='left'}={}){
325
- 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');
326
328
  // Explicit play/feeding always wins. Notifications never queue a second pet.
327
329
  if(active||pending||notice)return false;
328
- notice={kind,side,phase:'queued'};
330
+ if(gesture==='wall'&&!actor.canAttentionWall)return false;
331
+ const selected=gesture==='auto'?(actor.canAttentionWall&&noticeCount%2===1?'wall':'paw'):gesture;
332
+ noticeCount++;
333
+ notice={kind,side,gesture:selected,phase:'queued'};
329
334
  butterfly=null;queue=[];hold=0;holdIntent=null;gesture=null;waiting=null;
330
335
  actor.attend?.();
331
336
  return true;
@@ -0,0 +1,15 @@
1
+ // Loaded only by the default local Node host; browsers never import node:fs.
2
+ import {openSync,readSync,fstatSync,closeSync} from 'node:fs';
3
+ import {gunzipSync} from 'node:zlib';
4
+ import {indexedIndexLength,readIndexedIndex,createIndexedFrameStore} from './puppy-frame-indexed.mjs';
5
+ import {registerFrameStore} from './puppy-frame-store.mjs';
6
+
7
+ export function openFrameFile(url,options){
8
+ const fd=openSync(url,'r');let owned=true;
9
+ try{
10
+ const stat=fstatSync(fd);if(!stat.isFile())throw Error('Invalid frame file');
11
+ const read=(offset,size)=>{const out=new Uint8Array(size);let at=0;while(at<size){const n=readSync(fd,out,at,size-at,offset+at);if(!n)throw Error('Truncated frame file');at+=n;}return out;};
12
+ const header=read(0,20),length=indexedIndexLength(header),index=readIndexedIndex(read(0,length),stat.size);
13
+ const store=registerFrameStore(createIndexedFrameStore(index,{...options,read,expand:(b,n)=>gunzipSync(b,{maxOutputLength:Math.max(1,n)}),close:()=>closeSync(fd)}));owned=false;return store;
14
+ }finally{if(owned)closeSync(fd);}
15
+ }
@@ -0,0 +1,78 @@
1
+ // RVZ5: the approved RVQ5 rows, independently gzip-compressed for random access.
2
+ // Header/map match RVQ5; each 24-byte crop record stores x,y,w,h,offset,gzipLength.
3
+ // Offsets are relative to the end of the index. No new quantization or resampling.
4
+ import {unfilterRow} from './puppy-frame-predictive.mjs';
5
+ const HEADER=20,RECORD=24,MAX_PIXELS=16_777_216,MAX_INDEX=64*1024*1024,MAX_EXPANDED=512*1024*1024;
6
+ const fail=why=>{throw Error('Invalid indexed frames: '+why);};
7
+ const viewOf=b=>new DataView(b.buffer,b.byteOffset,b.byteLength);
8
+ export function indexedIndexLength(header){
9
+ if(!(header instanceof Uint8Array)||header.length<HEADER||String.fromCharCode(...header.subarray(0,4))!=='RVZ5')fail('header');
10
+ const v=viewOf(header),width=v.getUint32(4,true),height=v.getUint32(8,true),frames=v.getUint32(12,true),unique=v.getUint32(16,true);
11
+ if(!width||!height||width>16384||height>16384||width*height>MAX_PIXELS||!frames||!unique||unique>frames)fail('shape');
12
+ const length=HEADER+4*frames+RECORD*unique;
13
+ if(length>MAX_INDEX)fail('index size');return length;
14
+ }
15
+ export function readIndexedIndex(bytes,fileSize=bytes.length){
16
+ const length=indexedIndexLength(bytes);if(bytes.length<length||!Number.isSafeInteger(fileSize)||fileSize<length)fail('truncated index');
17
+ const v=viewOf(bytes),width=v.getUint32(4,true),height=v.getUint32(8,true),frameCount=v.getUint32(12,true),uniqueCount=v.getUint32(16,true);
18
+ const map=new Uint32Array(frameCount),used=new Uint8Array(uniqueCount),rects=new Uint32Array(uniqueCount*6);let payload=0,expanded=0;
19
+ for(let i=0;i<frameCount;i++){const u=v.getUint32(HEADER+i*4,true);if(u>=uniqueCount)fail('map');map[i]=u;used[u]=1;}
20
+ if(used.includes(0))fail('unreferenced frame');
21
+ for(let u=0;u<uniqueCount;u++){
22
+ const at=HEADER+frameCount*4+u*RECORD,r=Array.from({length:6},(_,i)=>v.getUint32(at+i*4,true)),[x,y,w,h,offset,size]=r;
23
+ if((w===0)!==(h===0)||(!w&&(x||y))||x+w>width||y+h>height)fail('rectangle');
24
+ if(offset!==payload||size<20)fail('offset');payload+=size;expanded+=h*(w+1);
25
+ if(expanded>MAX_EXPANDED)fail('expanded size');rects.set(r,u*6);
26
+ }
27
+ if(length+payload!==fileSize)fail('file size');
28
+ return {width,height,frameCount,uniqueCount,map,rects,indexBytes:length,expandedBytes:expanded,fileSize};
29
+ }
30
+ const display=Uint8Array.from({length:32},(_,q)=>Math.round(q*255/31));
31
+
32
+ // The host provides bounded positional reads and a synchronous gzip decoder.
33
+ // Only two reconstructed frames survive; compressed art stays on disk.
34
+ export function createIndexedFrameStore(index,{read,expand,close=()=>{},frameIndices}={}){
35
+ if(typeof read!=='function'||typeof expand!=='function')fail('reader');
36
+ const {width,height,frameCount,uniqueCount,map,rects,indexBytes}=index,n=width*height;
37
+ const retained=frameIndices===undefined?null:new Uint8Array(frameCount);
38
+ if(retained){if(!Array.isArray(frameIndices)||!frameIndices.length)fail('retained frames');for(const i of frameIndices){if(!Number.isInteger(i)||i<0||i>=frameCount)fail('retained frame index');retained[i]=1;}}
39
+ const slots=[{unique:-1,frame:null},{unique:-1,frame:null}],cur=new Uint8Array(width),prev=new Uint8Array(width);
40
+ let closed=false,decodes=0,hits=0,diskBytes=0;
41
+ return Object.freeze({width,height,frameCount,uniqueCount,byteLength:n*frameCount,residentPixelBytes:0,
42
+ get residentBytes(){return closed?0:map.byteLength+rects.byteLength+cur.byteLength+prev.byteLength+(retained?.byteLength??0)+slots.reduce((s,e)=>s+(e.frame?.byteLength??0),0);},
43
+ stats(){return {decodes,hits,cachedFrames:slots.filter(s=>s.frame).length,diskReads:decodes,diskBytes,closed};},
44
+ getFrame(i){
45
+ if(closed)throw Error('Frame store is disposed');
46
+ if(!Number.isInteger(i)||i<0||i>=frameCount)fail('frame index');if(retained&&!retained[i])fail('frame was not retained');
47
+ const u=map[i];if(slots[0].unique===u){hits++;return slots[0].frame;}if(slots[1].unique===u){hits++;slots.reverse();return slots[0].frame;}
48
+ const k=u*6,x=rects[k],y=rects[k+1],w=rects[k+2],h=rects[k+3],offset=rects[k+4],size=rects[k+5],expected=h*(w+1);
49
+ const compressed=read(indexBytes+offset,size);if(!(compressed instanceof Uint8Array)||compressed.length!==size)fail('short read');
50
+ const rows=expand(compressed,expected);if(!(rows instanceof Uint8Array)||rows.length!==expected)fail('expanded length');
51
+ // Mark the evicted slot invalid before parsing: a failed decode is never a hit.
52
+ const slot=slots.pop();slots.unshift(slot);slot.unique=-1;const frame=slot.frame??=new Uint8Array(n);frame.fill(0);prev.fill(0);
53
+ for(let r=0,at=0;r<h;r++){
54
+ const type=rows[at++];if(type>4)fail('filter');
55
+ unfilterRow(type,rows,at,cur,prev,w);at+=w;
56
+ for(let c=0;c<w;c++){
57
+ const q=cur[c];if(q>31)fail('quantized value');frame[(y+r)*width+x+c]=display[q];
58
+ }
59
+ prev.set(cur.subarray(0,w));
60
+ }
61
+ slot.unique=u;decodes++;diskBytes+=size;return frame;
62
+ },
63
+ dispose(){if(closed)return;closed=true;for(const slot of slots){slot.frame=null;slot.unique=-1;}close();},
64
+ });
65
+ }
66
+
67
+ // Portable/custom loaders retain the existing in-memory Q5 representation.
68
+ // The default local Node loader instead reads only the index and requested crops.
69
+ export async function expandIndexedArchive(bytes,expand){
70
+ const index=readIndexedIndex(bytes),{frameCount,uniqueCount,rects,indexBytes,expandedBytes}=index;
71
+ const out=new Uint8Array(indexBytes+expandedBytes);out.set(bytes.subarray(0,indexBytes));out.set([82,86,81,53]);const v=viewOf(out);let offset=0;
72
+ for(let u=0;u<uniqueCount;u++){
73
+ const k=u*6,size=rects[k+3]*(rects[k+2]+1),start=indexBytes+rects[k+4],rows=await expand(bytes.subarray(start,start+rects[k+5]),size);
74
+ if(!(rows instanceof Uint8Array)||rows.length!==size)fail('expanded length');
75
+ const at=HEADER+frameCount*4+u*RECORD;v.setUint32(at+16,offset,true);v.setUint32(at+20,size,true);out.set(rows,indexBytes+offset);offset+=size;
76
+ }
77
+ return out;
78
+ }
@@ -68,7 +68,7 @@ export function encodePredictiveFrames(rvf1,{filter}={}){
68
68
  }
69
69
 
70
70
  // Exact PNG inverse filter of one row into `cur` (bpp 1, integer arithmetic).
71
- function unfilterRow(type,src,at,cur,prev,w){
71
+ export function unfilterRow(type,src,at,cur,prev,w){
72
72
  switch(type){
73
73
  case 0:for(let x=0;x<w;x++)cur[x]=src[at+x];return;
74
74
  case 1:for(let x=0;x<w;x++)cur[x]=(src[at+x]+(x?cur[x-1]:0))&255;return;
@@ -11,6 +11,12 @@ import {isPredictiveFrames,readPredictiveFrames} from './puppy-frame-predictive.
11
11
  const MAGIC=[0x52,0x56,0x46,0x31],HEADER=20,RECORD=24,MAX_SIDE=16384;
12
12
  const stores=new WeakSet();
13
13
 
14
+ // Indexed local files obey the same borrowed two-frame contract as memory stores.
15
+ export function registerFrameStore(store){
16
+ if(!store||typeof store.getFrame!=='function'||typeof store.stats!=='function'||!Number.isInteger(store.width)||!Number.isInteger(store.height)||!Number.isInteger(store.frameCount))throw Error('Invalid frame store');
17
+ stores.add(store);return store;
18
+ }
19
+
14
20
  export function isPackedFrames(value){return stores.has(value);}
15
21
  export function isGrayFrameSource(value){return value instanceof Uint8Array||stores.has(value);}
16
22
 
@@ -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"}}});
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
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.progress,motion)]??motion.floorOffset??0):isInteraction||isAction||isBehavior||isSeat||isRear||isApproach?0:cleanGroundOffset(state,renderMeta),top=height*y-(300-floor)/320*side;
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);
Binary file
@@ -1,7 +1,7 @@
1
1
  /** A headless pet: the host owns input, time and terminal rendering. */
2
2
  export type FetchReturnStyle = 'auto' | 'brake' | 'trot' | 'run-trot';
3
3
  export interface PetOptions {
4
- /** Asset names are relative; return original file bytes (keep .gz files compressed). */
4
+ /** Relative names; return unchanged .rvz/.gz file bytes. Custom loaders use memory-backed art. */
5
5
  loadAsset?: (name: string) => Promise<ArrayBuffer | ArrayBufferView>;
6
6
  seed?: number;
7
7
  energy?: number;
@@ -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' | 'approaching' | '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. */
package/retrieviewer.mjs CHANGED
@@ -5,6 +5,7 @@ import {createSnappyTrickTimings} from './puppy-paper-trick-timing.mjs';
5
5
  import {createCompanionLife,FETCH_RETURN_STYLES} from './puppy-companion-life.mjs';
6
6
  import {paintCompanionObjects} from './puppy-companion-objects.mjs';
7
7
  import {readPackedFrames} from './puppy-frame-store.mjs';
8
+ import {expandIndexedArchive} from './puppy-frame-indexed.mjs';
8
9
  import {BAKED_MOTION} from './puppy-motion-tables.generated.mjs';
9
10
 
10
11
  // Embeddable autonomous puppy. Importing or creating has no DOM, timer, stdin/stdout
@@ -19,12 +20,12 @@ export const ART_PROFILES=Object.freeze(['original','q5']);
19
20
  export const PET_ASSETS=Object.freeze({
20
21
  // Kept as a legacy identifier only; createPet/getPetAssetFiles no longer load it.
21
22
  animal:'locomotion-puppy.animal',
22
- stride:'puppy-stride-tweens-q5.bin.gz',strideInfo:'puppy-stride-meta.json',stableInfo:'puppy-stable-meta.json',
23
+ stride:'puppy-stride-tweens-q5.rvz',strideInfo:'puppy-stride-meta.json',stableInfo:'puppy-stable-meta.json',
23
24
  rear:'puppy-paper-rear-gallop',approach:'puppy-paper-approach',seat:'puppy-paper-seat',arrivalSeat:'puppy-paper-arrival-seat',
24
25
  behaviors:'puppy-paper-behaviors',actions:'puppy-paper-actions-v9',interactions:'puppy-companion-interactions-v3',comfort:'puppy-companion-comfort',
25
26
  });
26
27
  const BUNDLES=['rear','approach','seat','arrivalSeat','behaviors','actions','interactions','comfort'];
27
- const frameFile=(base,profile)=>base+(profile==='q5'?'-q5.bin.gz':'-compact.bin.gz');
28
+ const frameFile=(base,profile)=>base+(profile==='q5'?'-q5.rvz':'-compact.bin.gz');
28
29
  /** Exact files a host/bundler must copy, including metadata. Never loads assets. */
29
30
  export function getPetAssetFiles(artProfile=DEFAULT_ART_PROFILE){
30
31
  if(!ART_PROFILES.includes(artProfile))throw RangeError('artProfile must be original or q5');
@@ -50,9 +51,9 @@ const bytesOf=(name,value)=>{
50
51
  if(ArrayBuffer.isView(value))return new Uint8Array(value.buffer,value.byteOffset,value.byteLength);
51
52
  throw TypeError(`loadAsset(${name}) must return an ArrayBuffer or typed bytes`);
52
53
  };
53
- async function gunzip(bytes){
54
+ async function gunzip(bytes,size){
54
55
  // Native Node gzip avoids Blob/Response/stream copies of every large cache.
55
- if(typeof process!=='undefined'&&process.versions?.node){const {gunzipSync}=await import('node:zlib');return gunzipSync(bytes);}
56
+ if(typeof process!=='undefined'&&process.versions?.node){const {gunzipSync}=await import('node:zlib');return gunzipSync(bytes,size===undefined?undefined:{maxOutputLength:Math.max(1,size)});}
56
57
  if(typeof DecompressionStream!=='undefined')return new Uint8Array(await new Response(new Blob([bytes]).stream().pipeThrough(new DecompressionStream('gzip'))).arrayBuffer());
57
58
  throw Error('This browser needs DecompressionStream for pet assets');
58
59
  }
@@ -75,8 +76,8 @@ function heldFrameKey(state,report,{columns,rows,cellAspect=.5,camera,poseFps=24
75
76
  report.ball,report.treat]);
76
77
  }
77
78
  async function loadPetAssets(loadAsset,artProfile){
78
- // Node keeps filtered crops compressed; only the existing two-frame LRU is
79
- // expanded. Browser bundles retain the portable bit-packed implementation.
79
+ // Default local Node hosts keep art on disk and reconstruct two frames per
80
+ // family. Custom/browser loaders retain the compatible memory-backed store.
80
81
  let codec;
81
82
  if(typeof process!=='undefined'&&process.versions?.node){
82
83
  const {deflateRawSync,inflateRawSync}=await import('node:zlib');
@@ -86,9 +87,18 @@ async function loadPetAssets(loadAsset,artProfile){
86
87
  }
87
88
  const load=async name=>bytesOf(name,await loadAsset(name));
88
89
  const json=async name=>JSON.parse(new TextDecoder().decode(await load(name)));
89
- const frames=async (name,options)=>readPackedFrames(await gunzip(await load(name)),{...options,codec});
90
- // One family at a time: never inflate all eight legacy-sized buffers together.
90
+ let openFrameFile;
91
+ if(artProfile==='q5'&&loadAsset===defaultLoadAsset&&new URL('.',import.meta.url).protocol==='file:'&&typeof process!=='undefined'&&process.versions?.node)({openFrameFile}=await import('./puppy-frame-file.mjs'));
92
+ const frames=async (name,options)=>{
93
+ if(name.endsWith('.rvz')){
94
+ if(openFrameFile)return openFrameFile(new URL(name,import.meta.url),options);
95
+ return readPackedFrames(await expandIndexedArchive(await load(name),gunzip),{...options,codec});
96
+ }
97
+ return readPackedFrames(await gunzip(await load(name)),{...options,codec});
98
+ };
99
+ // Read small indices locally; expand portable archives one family at a time.
91
100
  const data={assets:{}};
101
+ try{
92
102
  data.info=await json(PET_ASSETS.strideInfo);data.meta=await json(PET_ASSETS.stableInfo);
93
103
  data.cache=await frames(frameFile('puppy-stride-tweens',artProfile));
94
104
  for(const key of BUNDLES){
@@ -100,15 +110,17 @@ async function loadPetAssets(loadAsset,artProfile){
100
110
  data.assets[key]={info,bytes:await frames(frameFile(base,artProfile),options)};
101
111
  }
102
112
  return data;
113
+ }catch(error){disposeAssets(data);throw error;}
103
114
  }
115
+ function disposeAssets(data){data?.cache?.dispose?.();for(const family of Object.values(data?.assets??{}))family.bytes?.dispose?.();}
104
116
  async function acquireAssets(loadAsset,artProfile){
105
117
  let entry;
106
118
  if(loadAsset===defaultLoadAsset){entry=sharedAssets.get(artProfile);if(!entry){entry={users:0,promise:loadPetAssets(loadAsset,artProfile)};sharedAssets.set(artProfile,entry);}}
107
119
  else entry={users:0,promise:loadPetAssets(loadAsset,artProfile)};
108
120
  entry.users++;
109
121
  let released=false;
110
- const release=()=>{if(released)return;released=true;const previous=entry;entry=null;if(--previous.users===0&&sharedAssets.get(artProfile)===previous)sharedAssets.delete(artProfile);};
111
- try{return{data:await entry.promise,release};}catch(error){release();throw error;}
122
+ const release=()=>{if(released)return;released=true;const previous=entry;entry=null;if(--previous.users===0){if(sharedAssets.get(artProfile)===previous)sharedAssets.delete(artProfile);disposeAssets(previous.data);}};
123
+ try{const data=await entry.promise;entry.data=data;return{data,release};}catch(error){release();throw error;}
112
124
  }
113
125
 
114
126
  export async function createPet({loadAsset=defaultLoadAsset,seed,energy,pawTransport=true,artProfile=DEFAULT_ART_PROFILE,returnStyle='auto'}={}){
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file