@bitefoundry/retrieviewer 0.0.0-stage → 0.0.2
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 +43 -0
- package/ASSETS-LICENSE.md +58 -0
- package/ATTRIBUTION.md +54 -0
- package/EMBEDDING.md +96 -0
- package/INSTALLING.md +126 -0
- package/LICENSE +16 -0
- package/LICENSE-CODE +21 -0
- package/PLUGIN.md +110 -0
- package/PUPPY-MEMORY.md +57 -0
- package/PUPPY-Q5-COMPARISON.md +73 -0
- package/README.md +86 -2
- package/RELEASING.md +70 -0
- package/THIRD-PARTY-NOTICES.md +17 -0
- package/TRADEMARKS.md +21 -0
- package/WINDOWS-COMPANION.md +113 -0
- package/braille.mjs +45 -0
- package/examples/bridge.py +62 -0
- package/examples/embed.mjs +15 -0
- package/examples/live.mjs +40 -0
- package/examples/plugin.mjs +21 -0
- package/integrations/opencode/runtime.mjs +195 -0
- package/integrations/opencode/tui.tsx +59 -0
- package/integrations/windows-overlay/Overlay.cs +259 -0
- package/integrations/windows-overlay/desktop.mjs +87 -0
- package/integrations/windows-overlay/protocol.mjs +39 -0
- package/integrations/windows-overlay/worker.mjs +60 -0
- package/locomotion-core.mjs +21 -0
- package/locomotion-puppy.animal +0 -0
- package/package.json +131 -4
- package/pet-q5-manifest.json +118 -0
- package/puppy-clean.mjs +51 -0
- package/puppy-companion-interactions-v3-q5.bin.gz +0 -0
- package/puppy-companion-interactions-v3.json +1 -0
- package/puppy-companion-life.mjs +182 -0
- package/puppy-companion-objects.mjs +30 -0
- package/puppy-companion-sprites.mjs +14 -0
- package/puppy-continuous.mjs +57 -0
- package/puppy-face.mjs +46 -0
- package/puppy-frame-predictive.mjs +147 -0
- package/puppy-frame-store.mjs +108 -0
- package/puppy-mouth-anchor.json +1 -0
- package/puppy-mouth-anchor.mjs +33 -0
- package/puppy-paper-actions-v9-q5.bin.gz +0 -0
- package/puppy-paper-actions-v9.json +1 -0
- package/puppy-paper-actions.mjs +48 -0
- package/puppy-paper-approach-q5.bin.gz +0 -0
- package/puppy-paper-approach.json +1 -0
- package/puppy-paper-area.mjs +15 -0
- package/puppy-paper-arrival-seat-q5.bin.gz +0 -0
- package/puppy-paper-arrival-seat.json +1 -0
- package/puppy-paper-behaviors-q5.bin.gz +0 -0
- package/puppy-paper-behaviors.json +1 -0
- package/puppy-paper-behaviors.mjs +8 -0
- package/puppy-paper-contact.mjs +103 -0
- package/puppy-paper-director.mjs +21 -0
- package/puppy-paper-paw-transport.mjs +76 -0
- package/puppy-paper-rear-gallop-q5.bin.gz +0 -0
- package/puppy-paper-rear-gallop.json +1 -0
- package/puppy-paper-seat-q5.bin.gz +0 -0
- package/puppy-paper-seat.json +14 -0
- package/puppy-paper-seat.mjs +13 -0
- package/puppy-paper-trick-timing.mjs +58 -0
- package/puppy-paper-world.mjs +108 -0
- package/puppy-paper.mjs +271 -0
- package/puppy-stable-meta.json +1606 -0
- package/puppy-stable.mjs +72 -0
- package/puppy-stride-meta.json +343 -0
- package/puppy-stride-tweens-q5.bin.gz +0 -0
- package/puppy-zoomies.mjs +27 -0
- package/puppy-zoomies30.mjs +12 -0
- package/retrieviewer-cli.mjs +94 -0
- package/retrieviewer-config.mjs +49 -0
- package/retrieviewer-install.mjs +157 -0
- package/retrieviewer-plugin.d.mts +44 -0
- package/retrieviewer-plugin.mjs +97 -0
- package/retrieviewer-stdio.mjs +38 -0
- package/retrieviewer.d.mts +85 -0
- package/retrieviewer.mjs +142 -0
- package/vendor/procedural-animals/LICENSE +21 -0
- package/vendor/procedural-animals/package.json +40 -0
- package/vendor/procedural-animals/src/animal.js +146 -0
- package/vendor/procedural-animals/src/bake.js +51 -0
- package/vendor/procedural-animals/src/build.js +81 -0
- package/vendor/procedural-animals/src/core/build/coatKit.js +121 -0
- package/vendor/procedural-animals/src/core/build/featherCards.js +189 -0
- package/vendor/procedural-animals/src/core/build/finEdges.js +85 -0
- package/vendor/procedural-animals/src/core/build/furSlope.js +115 -0
- package/vendor/procedural-animals/src/core/build/mesh.js +67 -0
- package/vendor/procedural-animals/src/core/build/pipeline.js +272 -0
- package/vendor/procedural-animals/src/core/build/seams.js +183 -0
- package/vendor/procedural-animals/src/core/build/warp.js +112 -0
- package/vendor/procedural-animals/src/core/build/weights.js +393 -0
- package/vendor/procedural-animals/src/core/math/vec.js +81 -0
- package/vendor/procedural-animals/src/core/motion/actions.js +800 -0
- package/vendor/procedural-animals/src/core/motion/bird.js +3063 -0
- package/vendor/procedural-animals/src/core/motion/birdActions.js +1059 -0
- package/vendor/procedural-animals/src/core/motion/common.js +158 -0
- package/vendor/procedural-animals/src/core/motion/index.js +22 -0
- package/vendor/procedural-animals/src/core/motion/quadruped.js +2875 -0
- package/vendor/procedural-animals/src/core/motion/snake.js +1594 -0
- package/vendor/procedural-animals/src/core/motion/spider.js +1810 -0
- package/vendor/procedural-animals/src/core/motion/swimmer.js +1047 -0
- package/vendor/procedural-animals/src/core/motion/swimmerActions.js +613 -0
- package/vendor/procedural-animals/src/core/render/animalObject.js +262 -0
- package/vendor/procedural-animals/src/core/render/coatMaterial.js +1301 -0
- package/vendor/procedural-animals/src/core/render/dqs.js +159 -0
- package/vendor/procedural-animals/src/core/render/eyes.js +676 -0
- package/vendor/procedural-animals/src/core/render/membranes.js +77 -0
- package/vendor/procedural-animals/src/core/render/skeleton.js +41 -0
- package/vendor/procedural-animals/src/core/rig/bird.js +327 -0
- package/vendor/procedural-animals/src/core/rig/quadruped.js +76 -0
- package/vendor/procedural-animals/src/core/rig/rig.js +79 -0
- package/vendor/procedural-animals/src/core/rig/snake.js +76 -0
- package/vendor/procedural-animals/src/core/rig/spider.js +110 -0
- package/vendor/procedural-animals/src/core/rig/swimmer.js +181 -0
- package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +53 -0
- package/vendor/procedural-animals/src/core/sdf/mesher.js +238 -0
- package/vendor/procedural-animals/src/core/sdf/sdf.js +263 -0
- package/vendor/procedural-animals/src/index.d.ts +98 -0
- package/vendor/procedural-animals/src/index.js +29 -0
- package/vendor/procedural-animals/src/registry.js +48 -0
- package/vendor/procedural-animals/src/species/bear/behaviour.js +463 -0
- package/vendor/procedural-animals/src/species/bear/claws.js +147 -0
- package/vendor/procedural-animals/src/species/bear/coat.js +726 -0
- package/vendor/procedural-animals/src/species/bear/index.js +139 -0
- package/vendor/procedural-animals/src/species/bear/motion.js +112 -0
- package/vendor/procedural-animals/src/species/bear/regions.js +78 -0
- package/vendor/procedural-animals/src/species/bear/rig.js +112 -0
- package/vendor/procedural-animals/src/species/bear/sculpt.js +272 -0
- package/vendor/procedural-animals/src/species/boar/behaviour.js +335 -0
- package/vendor/procedural-animals/src/species/boar/coat.js +372 -0
- package/vendor/procedural-animals/src/species/boar/index.js +110 -0
- package/vendor/procedural-animals/src/species/boar/motion.js +85 -0
- package/vendor/procedural-animals/src/species/boar/regions.js +88 -0
- package/vendor/procedural-animals/src/species/boar/rig.js +111 -0
- package/vendor/procedural-animals/src/species/boar/sculpt.js +285 -0
- package/vendor/procedural-animals/src/species/cat/behaviour.js +559 -0
- package/vendor/procedural-animals/src/species/cat/coat.js +841 -0
- package/vendor/procedural-animals/src/species/cat/index.js +211 -0
- package/vendor/procedural-animals/src/species/cat/motion.js +101 -0
- package/vendor/procedural-animals/src/species/cat/regions.js +82 -0
- package/vendor/procedural-animals/src/species/cat/rig.js +100 -0
- package/vendor/procedural-animals/src/species/cat/sculpt.js +266 -0
- package/vendor/procedural-animals/src/species/cat/whiskers.js +110 -0
- package/vendor/procedural-animals/src/species/cheetah/coat.js +427 -0
- package/vendor/procedural-animals/src/species/cheetah/index.js +51 -0
- package/vendor/procedural-animals/src/species/cheetah/joints.js +3 -0
- package/vendor/procedural-animals/src/species/cheetah/motion.js +77 -0
- package/vendor/procedural-animals/src/species/cheetah/regions.js +95 -0
- package/vendor/procedural-animals/src/species/cheetah/rig.js +66 -0
- package/vendor/procedural-animals/src/species/cheetah/sculpt.js +158 -0
- package/vendor/procedural-animals/src/species/chicken/coat.js +313 -0
- package/vendor/procedural-animals/src/species/chicken/coverts.js +320 -0
- package/vendor/procedural-animals/src/species/chicken/index.js +110 -0
- package/vendor/procedural-animals/src/species/chicken/motion.js +177 -0
- package/vendor/procedural-animals/src/species/chicken/regions.js +66 -0
- package/vendor/procedural-animals/src/species/chicken/rig.js +144 -0
- package/vendor/procedural-animals/src/species/chicken/sculpt.js +389 -0
- package/vendor/procedural-animals/src/species/chicken/wingLook.js +66 -0
- package/vendor/procedural-animals/src/species/chicken/wingStack.js +124 -0
- package/vendor/procedural-animals/src/species/cow/behaviour.js +521 -0
- package/vendor/procedural-animals/src/species/cow/coat.js +465 -0
- package/vendor/procedural-animals/src/species/cow/index.js +118 -0
- package/vendor/procedural-animals/src/species/cow/motion.js +81 -0
- package/vendor/procedural-animals/src/species/cow/regions.js +98 -0
- package/vendor/procedural-animals/src/species/cow/rig.js +116 -0
- package/vendor/procedural-animals/src/species/cow/sculpt.js +339 -0
- package/vendor/procedural-animals/src/species/crow/coat.js +145 -0
- package/vendor/procedural-animals/src/species/crow/index.js +70 -0
- package/vendor/procedural-animals/src/species/crow/joints.js +3 -0
- package/vendor/procedural-animals/src/species/crow/motion.js +101 -0
- package/vendor/procedural-animals/src/species/crow/regions.js +50 -0
- package/vendor/procedural-animals/src/species/crow/rig.js +83 -0
- package/vendor/procedural-animals/src/species/crow/sculpt.js +118 -0
- package/vendor/procedural-animals/src/species/deer/behaviour.js +513 -0
- package/vendor/procedural-animals/src/species/deer/coat.js +391 -0
- package/vendor/procedural-animals/src/species/deer/index.js +106 -0
- package/vendor/procedural-animals/src/species/deer/motion.js +97 -0
- package/vendor/procedural-animals/src/species/deer/regions.js +60 -0
- package/vendor/procedural-animals/src/species/deer/rig.js +124 -0
- package/vendor/procedural-animals/src/species/deer/sculpt.js +297 -0
- package/vendor/procedural-animals/src/species/dog/behaviour.js +521 -0
- package/vendor/procedural-animals/src/species/dog/coat.js +495 -0
- package/vendor/procedural-animals/src/species/dog/index.js +144 -0
- package/vendor/procedural-animals/src/species/dog/motion.js +118 -0
- package/vendor/procedural-animals/src/species/dog/regions.js +61 -0
- package/vendor/procedural-animals/src/species/dog/rig.js +129 -0
- package/vendor/procedural-animals/src/species/dog/sculpt.js +246 -0
- package/vendor/procedural-animals/src/species/eagle/coat.js +250 -0
- package/vendor/procedural-animals/src/species/eagle/index.js +76 -0
- package/vendor/procedural-animals/src/species/eagle/joints.js +3 -0
- package/vendor/procedural-animals/src/species/eagle/motion.js +137 -0
- package/vendor/procedural-animals/src/species/eagle/regions.js +57 -0
- package/vendor/procedural-animals/src/species/eagle/rig.js +107 -0
- package/vendor/procedural-animals/src/species/eagle/sculpt.js +137 -0
- package/vendor/procedural-animals/src/species/fish/coat.js +271 -0
- package/vendor/procedural-animals/src/species/fish/index.js +88 -0
- package/vendor/procedural-animals/src/species/fish/motion.js +92 -0
- package/vendor/procedural-animals/src/species/fish/regions.js +27 -0
- package/vendor/procedural-animals/src/species/fish/rig.js +143 -0
- package/vendor/procedural-animals/src/species/fish/sculpt.js +214 -0
- package/vendor/procedural-animals/src/species/fish/variants.js +126 -0
- package/vendor/procedural-animals/src/species/fox/behaviour.js +314 -0
- package/vendor/procedural-animals/src/species/fox/coat.js +444 -0
- package/vendor/procedural-animals/src/species/fox/index.js +120 -0
- package/vendor/procedural-animals/src/species/fox/motion.js +81 -0
- package/vendor/procedural-animals/src/species/fox/regions.js +59 -0
- package/vendor/procedural-animals/src/species/fox/rig.js +91 -0
- package/vendor/procedural-animals/src/species/fox/sculpt.js +202 -0
- package/vendor/procedural-animals/src/species/frog/behaviour.js +590 -0
- package/vendor/procedural-animals/src/species/frog/coat.js +305 -0
- package/vendor/procedural-animals/src/species/frog/index.js +97 -0
- package/vendor/procedural-animals/src/species/frog/motion.js +69 -0
- package/vendor/procedural-animals/src/species/frog/regions.js +46 -0
- package/vendor/procedural-animals/src/species/frog/rig.js +156 -0
- package/vendor/procedural-animals/src/species/frog/sculpt.js +240 -0
- package/vendor/procedural-animals/src/species/goat/behaviour.js +509 -0
- package/vendor/procedural-animals/src/species/goat/coat.js +590 -0
- package/vendor/procedural-animals/src/species/goat/index.js +149 -0
- package/vendor/procedural-animals/src/species/goat/motion.js +95 -0
- package/vendor/procedural-animals/src/species/goat/regions.js +98 -0
- package/vendor/procedural-animals/src/species/goat/rig.js +181 -0
- package/vendor/procedural-animals/src/species/goat/sculpt.js +547 -0
- package/vendor/procedural-animals/src/species/horse/coat.js +361 -0
- package/vendor/procedural-animals/src/species/horse/coatSeam.js +122 -0
- package/vendor/procedural-animals/src/species/horse/index.js +80 -0
- package/vendor/procedural-animals/src/species/horse/motion.js +245 -0
- package/vendor/procedural-animals/src/species/horse/regions.js +60 -0
- package/vendor/procedural-animals/src/species/horse/rig.js +117 -0
- package/vendor/procedural-animals/src/species/horse/sculpt.js +316 -0
- package/vendor/procedural-animals/src/species/horse/seamWeights.js +272 -0
- package/vendor/procedural-animals/src/species/lion/behaviour.js +509 -0
- package/vendor/procedural-animals/src/species/lion/coat.js +1016 -0
- package/vendor/procedural-animals/src/species/lion/index.js +111 -0
- package/vendor/procedural-animals/src/species/lion/motion.js +87 -0
- package/vendor/procedural-animals/src/species/lion/regions.js +106 -0
- package/vendor/procedural-animals/src/species/lion/rig.js +110 -0
- package/vendor/procedural-animals/src/species/lion/sculpt.js +384 -0
- package/vendor/procedural-animals/src/species/lion/whiskers.js +132 -0
- package/vendor/procedural-animals/src/species/pig/behaviour.js +575 -0
- package/vendor/procedural-animals/src/species/pig/coat.js +730 -0
- package/vendor/procedural-animals/src/species/pig/ears.js +242 -0
- package/vendor/procedural-animals/src/species/pig/index.js +161 -0
- package/vendor/procedural-animals/src/species/pig/motion.js +105 -0
- package/vendor/procedural-animals/src/species/pig/regions.js +100 -0
- package/vendor/procedural-animals/src/species/pig/rig.js +152 -0
- package/vendor/procedural-animals/src/species/pig/sculpt.js +382 -0
- package/vendor/procedural-animals/src/species/rabbit/behaviour.js +605 -0
- package/vendor/procedural-animals/src/species/rabbit/coat.js +285 -0
- package/vendor/procedural-animals/src/species/rabbit/index.js +85 -0
- package/vendor/procedural-animals/src/species/rabbit/motion.js +85 -0
- package/vendor/procedural-animals/src/species/rabbit/regions.js +48 -0
- package/vendor/procedural-animals/src/species/rabbit/rig.js +99 -0
- package/vendor/procedural-animals/src/species/rabbit/sculpt.js +148 -0
- package/vendor/procedural-animals/src/species/rat/behaviour.js +539 -0
- package/vendor/procedural-animals/src/species/rat/coat.js +341 -0
- package/vendor/procedural-animals/src/species/rat/index.js +111 -0
- package/vendor/procedural-animals/src/species/rat/motion.js +90 -0
- package/vendor/procedural-animals/src/species/rat/regions.js +92 -0
- package/vendor/procedural-animals/src/species/rat/rig.js +112 -0
- package/vendor/procedural-animals/src/species/rat/sculpt.js +163 -0
- package/vendor/procedural-animals/src/species/rat/whiskers.js +119 -0
- package/vendor/procedural-animals/src/species/shark/coat.js +383 -0
- package/vendor/procedural-animals/src/species/shark/index.js +104 -0
- package/vendor/procedural-animals/src/species/shark/motion.js +69 -0
- package/vendor/procedural-animals/src/species/shark/regions.js +34 -0
- package/vendor/procedural-animals/src/species/shark/rig.js +194 -0
- package/vendor/procedural-animals/src/species/shark/sculpt.js +343 -0
- package/vendor/procedural-animals/src/species/shark/variants.js +105 -0
- package/vendor/procedural-animals/src/species/sheep/behaviour.js +522 -0
- package/vendor/procedural-animals/src/species/sheep/coat.js +529 -0
- package/vendor/procedural-animals/src/species/sheep/index.js +152 -0
- package/vendor/procedural-animals/src/species/sheep/motion.js +86 -0
- package/vendor/procedural-animals/src/species/sheep/neck.js +41 -0
- package/vendor/procedural-animals/src/species/sheep/regions.js +62 -0
- package/vendor/procedural-animals/src/species/sheep/rig.js +163 -0
- package/vendor/procedural-animals/src/species/sheep/sculpt.js +542 -0
- package/vendor/procedural-animals/src/species/snake/coat.js +315 -0
- package/vendor/procedural-animals/src/species/snake/index.js +73 -0
- package/vendor/procedural-animals/src/species/snake/motion.js +51 -0
- package/vendor/procedural-animals/src/species/snake/regions.js +51 -0
- package/vendor/procedural-animals/src/species/snake/rig.js +108 -0
- package/vendor/procedural-animals/src/species/snake/sculpt.js +122 -0
- package/vendor/procedural-animals/src/species/spider/coat.js +279 -0
- package/vendor/procedural-animals/src/species/spider/index.js +78 -0
- package/vendor/procedural-animals/src/species/spider/motion.js +72 -0
- package/vendor/procedural-animals/src/species/spider/regions.js +87 -0
- package/vendor/procedural-animals/src/species/spider/rig.js +118 -0
- package/vendor/procedural-animals/src/species/spider/sculpt.js +182 -0
- package/vendor/procedural-animals/src/species/wolf/behaviour.js +160 -0
- package/vendor/procedural-animals/src/species/wolf/coat.js +749 -0
- package/vendor/procedural-animals/src/species/wolf/index.js +107 -0
- package/vendor/procedural-animals/src/species/wolf/motion.js +80 -0
- package/vendor/procedural-animals/src/species/wolf/regions.js +57 -0
- package/vendor/procedural-animals/src/species/wolf/rig.js +87 -0
- package/vendor/procedural-animals/src/species/wolf/sculpt.js +339 -0
- package/vendor/procedural-animals/src/worker.js +29 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Private detached worker, started only by the explicit `desktop` command.
|
|
2
|
+
import {spawn} from 'node:child_process';
|
|
3
|
+
import {createServer} from 'node:net';
|
|
4
|
+
import {createInterface} from 'node:readline';
|
|
5
|
+
import {open,unlink,readFile} from 'node:fs/promises';
|
|
6
|
+
import {randomBytes,randomUUID} from 'node:crypto';
|
|
7
|
+
import {prepareRoot,noLink} from './desktop.mjs';
|
|
8
|
+
import {createFramePump} from './protocol.mjs';
|
|
9
|
+
|
|
10
|
+
let helper,pump,timer,server,session,paths,owned=false,stopping=false,frames=0,paintedFrames=0,visible=false,selected=false,pickerVisible=false,pendingViewport=null,lastInteraction=null;
|
|
11
|
+
const sendParent=message=>{if(process.connected)process.send(message);};
|
|
12
|
+
async function stop(){
|
|
13
|
+
if(stopping)return;stopping=true;clearInterval(timer);pump?.dispose();
|
|
14
|
+
if(helper&&!helper.killed){try{helper.stdin.end(JSON.stringify({type:'quit'})+'\n');}catch{}}
|
|
15
|
+
if(server)server.close();
|
|
16
|
+
if(owned)try{const current=JSON.parse(await readFile(paths.session,'utf8'));if(current.token===session.token)await unlink(paths.session);}catch{}
|
|
17
|
+
// A wedged painter is our own child only, never the selected terminal.
|
|
18
|
+
const watchdog=setTimeout(()=>{helper?.kill();process.exit(0);},2500);watchdog.unref();
|
|
19
|
+
if(!helper||helper.exitCode!==null)process.exitCode=0;
|
|
20
|
+
}
|
|
21
|
+
process.on('SIGTERM',stop);process.on('SIGINT',stop);process.on('message',m=>{if(m?.command==='abort')stop();});
|
|
22
|
+
try{
|
|
23
|
+
paths=await prepareRoot();await noLink(paths.session);
|
|
24
|
+
session={owner:'bitefoundry-retrieviewer-overlay-v1',pid:process.pid,pipe:'\\\\.\\pipe\\retrieviewer-overlay-'+randomUUID(),token:randomBytes(32).toString('hex')};
|
|
25
|
+
const record=await open(paths.session,'wx',0o600);owned=true;try{await record.writeFile(JSON.stringify(session)+'\n');}finally{await record.close();}
|
|
26
|
+
server=createServer(socket=>{
|
|
27
|
+
socket.setTimeout(1500,()=>socket.destroy());let body='';
|
|
28
|
+
socket.on('error',()=>{});socket.on('data',bytes=>{
|
|
29
|
+
body+=bytes.toString('utf8');if(body.length>2048)return socket.destroy();if(!body.includes('\n'))return;
|
|
30
|
+
let command;try{command=JSON.parse(body.split('\n')[0]);}catch{return socket.destroy();}
|
|
31
|
+
if(command.token!==session.token||!['status','stop'].includes(command.command))return socket.destroy();
|
|
32
|
+
socket.end(JSON.stringify(command.command==='stop'?{stopped:true}:{running:true,reachable:true,selected,visible,pickerVisible,frames,paintedFrames,lastInteraction,pid:process.pid,painterPid:helper?.pid,rssBytes:process.memoryUsage().rss})+'\n');
|
|
33
|
+
if(command.command==='stop')stop();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
await new Promise((resolve,reject)=>{server.once('error',reject);server.listen(session.pipe,resolve);});
|
|
37
|
+
// GUI-subsystem exe: no console to hide. SW_HIDE here also hides its first UI.
|
|
38
|
+
helper=spawn(process.argv[2],process.argv[3]==='--ipc-test'?['--ipc-test']:[],{windowsHide:false,stdio:['pipe','pipe','pipe']});
|
|
39
|
+
helper.stdin.on('error',()=>stop());helper.stderr.resume();helper.once('error',error=>{sendParent({error:error.message});stop();});
|
|
40
|
+
helper.once('exit',code=>{if(!stopping)sendParent({error:'Windows painter exited ('+code+')'});stop();});
|
|
41
|
+
const write=message=>{if(!stopping&&!helper.stdin.destroyed)helper.stdin.write(JSON.stringify(message)+'\n');};
|
|
42
|
+
const reader=createInterface({input:helper.stdout});
|
|
43
|
+
reader.on('line',line=>{
|
|
44
|
+
if(line.length>100000)return stop();let m;try{m=JSON.parse(line);}catch{return stop();}
|
|
45
|
+
try{
|
|
46
|
+
if(m.type==='ready'){pickerVisible=m.pickerVisible===true;sendParent({running:true,windowPicker:pickerVisible,mode:'windows-overlay',pid:process.pid});}
|
|
47
|
+
else if(m.type==='picker')pickerVisible=m.visible===true;
|
|
48
|
+
else if(m.type==='viewport'){pendingViewport=m;visible=m.visible;selected=m.selected===true;pump?.viewport(m);}
|
|
49
|
+
else if(m.type==='ack'){frames++;if(m.painted)paintedFrames++;pump?.ack();}
|
|
50
|
+
else if(m.type==='pause')pump?.pause(m.paused);
|
|
51
|
+
else if(m.type==='interact'){const accepted=pump?.interact(m.kind)??false;lastInteraction={kind:m.kind,accepted};write({type:'interaction',kind:m.kind,accepted});}
|
|
52
|
+
else if(m.type==='quit')stop();
|
|
53
|
+
}catch(error){write({type:'error',message:error.message});stop();}
|
|
54
|
+
});
|
|
55
|
+
const {createPet}=await import('../../retrieviewer.mjs');const pet=await createPet();
|
|
56
|
+
if(stopping)pet.dispose();else{
|
|
57
|
+
pump=createFramePump({pet,send:write});if(pendingViewport)pump.viewport(pendingViewport);
|
|
58
|
+
write({type:'loaded'});timer=setInterval(()=>{try{pump.tick();}catch(error){write({type:'error',message:error.message});stop();}},1000/30);
|
|
59
|
+
}
|
|
60
|
+
}catch(error){sendParent({error:error.message});await stop();}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import {createAnimal} from './vendor/procedural-animals/src/index.js';
|
|
3
|
+
export const LAB_OPTIONS={variant:'retriever',age:'juvenile',seed:2,quality:'low',worker:false,overrides:{colour:'yellow',stanceSoftMargin:.005}};
|
|
4
|
+
export async function makeLabAnimal(extra={}){
|
|
5
|
+
return createAnimal('dog',{...LAB_OPTIONS,...extra,overrides:{...LAB_OPTIONS.overrides,...extra.overrides}});
|
|
6
|
+
}
|
|
7
|
+
// Never translate the mesh externally. The gait engine owns root motion + IK.
|
|
8
|
+
export function makeLabController(animal){
|
|
9
|
+
let target=null,speed=animal.gears.walk;
|
|
10
|
+
return {get target(){return target;},get speed(){return speed;},setSpeed(kind){
|
|
11
|
+
if(!['walk','trot','gallop'].includes(kind))throw Error('Unknown gait');
|
|
12
|
+
speed=animal.gears[kind];if(target)animal.moveTo(target,{speed});
|
|
13
|
+
},go(x,z){
|
|
14
|
+
if(![x,z].every(Number.isFinite))throw Error('Invalid ground target');
|
|
15
|
+
target=new THREE.Vector3(Math.max(-.8,Math.min(.8,x)),0,Math.max(-1.7,Math.min(.3,z)));
|
|
16
|
+
animal.stopAction();animal.moveTo(target,{speed});
|
|
17
|
+
},stop(){target=null;animal.stop();},update(dt){
|
|
18
|
+
if(!Number.isFinite(dt)||dt<0||dt>.1)throw Error('Invalid lab step');animal.update(dt);
|
|
19
|
+
if(target&&animal.position.distanceTo(target)<.025&&animal.speed<.03){target=null;animal.stop();}
|
|
20
|
+
}};
|
|
21
|
+
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,133 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitefoundry/retrieviewer",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "A fluffy Braille desktop companion for Windows apps, plus an embeddable TUI pet. Give it a ball or a treat.",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"homepage": "https://github.com/BiteFoundry",
|
|
7
|
+
"keywords": ["tui", "braille", "pet", "retriever", "opencode", "desktop-pet", "windows", "overlay"],
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public",
|
|
10
|
+
"registry": "https://registry.npmjs.org/",
|
|
11
|
+
"tag": "latest"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"private": false,
|
|
17
|
+
"type": "module",
|
|
18
|
+
"types": "./retrieviewer.d.mts",
|
|
19
|
+
"bin": {
|
|
20
|
+
"retrieviewer": "retrieviewer-cli.mjs",
|
|
21
|
+
"retrieviewer-stdio": "retrieviewer-stdio.mjs"
|
|
22
|
+
},
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./retrieviewer.d.mts",
|
|
26
|
+
"default": "./retrieviewer.mjs"
|
|
27
|
+
},
|
|
28
|
+
"./plugin": {
|
|
29
|
+
"types": "./retrieviewer-plugin.d.mts",
|
|
30
|
+
"default": "./retrieviewer-plugin.mjs"
|
|
31
|
+
},
|
|
32
|
+
"./tui": "./integrations/opencode/tui.tsx",
|
|
33
|
+
"./opencode/tui": "./integrations/opencode/tui.tsx",
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"LICENSE-CODE",
|
|
39
|
+
"ASSETS-LICENSE.md",
|
|
40
|
+
"ATTRIBUTION.md",
|
|
41
|
+
"ASSET-PROVENANCE.md",
|
|
42
|
+
"THIRD-PARTY-NOTICES.md",
|
|
43
|
+
"TRADEMARKS.md",
|
|
44
|
+
"RELEASING.md",
|
|
45
|
+
"retrieviewer.mjs",
|
|
46
|
+
"retrieviewer.d.mts",
|
|
47
|
+
"retrieviewer-stdio.mjs",
|
|
48
|
+
"retrieviewer-plugin.mjs",
|
|
49
|
+
"retrieviewer-plugin.d.mts",
|
|
50
|
+
"retrieviewer-cli.mjs",
|
|
51
|
+
"retrieviewer-install.mjs",
|
|
52
|
+
"retrieviewer-config.mjs",
|
|
53
|
+
"integrations/opencode/tui.tsx",
|
|
54
|
+
"integrations/opencode/runtime.mjs",
|
|
55
|
+
"integrations/windows-overlay/protocol.mjs",
|
|
56
|
+
"integrations/windows-overlay/desktop.mjs",
|
|
57
|
+
"integrations/windows-overlay/worker.mjs",
|
|
58
|
+
"integrations/windows-overlay/Overlay.cs",
|
|
59
|
+
"WINDOWS-COMPANION.md",
|
|
60
|
+
"INSTALLING.md",
|
|
61
|
+
"PLUGIN.md",
|
|
62
|
+
"EMBEDDING.md",
|
|
63
|
+
"PUPPY-MEMORY.md",
|
|
64
|
+
"PUPPY-Q5-COMPARISON.md",
|
|
65
|
+
"examples/embed.mjs",
|
|
66
|
+
"examples/live.mjs",
|
|
67
|
+
"examples/plugin.mjs",
|
|
68
|
+
"examples/bridge.py",
|
|
69
|
+
"locomotion-core.mjs",
|
|
70
|
+
"locomotion-puppy.animal",
|
|
71
|
+
"braille.mjs",
|
|
72
|
+
"puppy-frame-store.mjs",
|
|
73
|
+
"puppy-frame-predictive.mjs",
|
|
74
|
+
"pet-q5-manifest.json",
|
|
75
|
+
"puppy-paper.mjs",
|
|
76
|
+
"puppy-paper-world.mjs",
|
|
77
|
+
"puppy-paper-contact.mjs",
|
|
78
|
+
"puppy-paper-seat.mjs",
|
|
79
|
+
"puppy-paper-director.mjs",
|
|
80
|
+
"puppy-paper-behaviors.mjs",
|
|
81
|
+
"puppy-paper-area.mjs",
|
|
82
|
+
"puppy-paper-actions.mjs",
|
|
83
|
+
"puppy-paper-trick-timing.mjs",
|
|
84
|
+
"puppy-paper-paw-transport.mjs",
|
|
85
|
+
"puppy-companion-life.mjs",
|
|
86
|
+
"puppy-companion-objects.mjs",
|
|
87
|
+
"puppy-companion-sprites.mjs",
|
|
88
|
+
"puppy-mouth-anchor.mjs",
|
|
89
|
+
"puppy-mouth-anchor.json",
|
|
90
|
+
"puppy-clean.mjs",
|
|
91
|
+
"puppy-stable.mjs",
|
|
92
|
+
"puppy-face.mjs",
|
|
93
|
+
"puppy-continuous.mjs",
|
|
94
|
+
"puppy-zoomies.mjs",
|
|
95
|
+
"puppy-zoomies30.mjs",
|
|
96
|
+
"puppy-stride-tweens-q5.bin.gz",
|
|
97
|
+
"puppy-stride-meta.json",
|
|
98
|
+
"puppy-stable-meta.json",
|
|
99
|
+
"puppy-paper-rear-gallop-q5.bin.gz",
|
|
100
|
+
"puppy-paper-rear-gallop.json",
|
|
101
|
+
"puppy-paper-approach-q5.bin.gz",
|
|
102
|
+
"puppy-paper-approach.json",
|
|
103
|
+
"puppy-paper-seat-q5.bin.gz",
|
|
104
|
+
"puppy-paper-seat.json",
|
|
105
|
+
"puppy-paper-arrival-seat-q5.bin.gz",
|
|
106
|
+
"puppy-paper-arrival-seat.json",
|
|
107
|
+
"puppy-paper-behaviors-q5.bin.gz",
|
|
108
|
+
"puppy-paper-behaviors.json",
|
|
109
|
+
"puppy-paper-actions-v9-q5.bin.gz",
|
|
110
|
+
"puppy-paper-actions-v9.json",
|
|
111
|
+
"puppy-companion-interactions-v3-q5.bin.gz",
|
|
112
|
+
"puppy-companion-interactions-v3.json",
|
|
113
|
+
"vendor/procedural-animals/src",
|
|
114
|
+
"vendor/procedural-animals/LICENSE",
|
|
115
|
+
"vendor/procedural-animals/package.json"
|
|
116
|
+
],
|
|
117
|
+
"scripts": {
|
|
118
|
+
"start": "node server.mjs",
|
|
119
|
+
"terminal": "node terminal.mjs",
|
|
120
|
+
"pet": "node puppy-terminal.mjs",
|
|
121
|
+
"pet:companion": "node examples/live.mjs",
|
|
122
|
+
"pet:desktop": "node retrieviewer-cli.mjs desktop",
|
|
123
|
+
"test": "node --test \"*.test.mjs\"",
|
|
124
|
+
"test:locomotion": "node check-locomotion.mjs",
|
|
125
|
+
"test:package": "node check-pet-package.mjs",
|
|
126
|
+
"release:check": "node tools/check-release.mjs",
|
|
127
|
+
"prepublishOnly": "npm run release:check"
|
|
128
|
+
},
|
|
129
|
+
"dependencies": {
|
|
130
|
+
"jsonc-parser": "3.3.1",
|
|
131
|
+
"three": "0.186.1"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"levels": 32,
|
|
4
|
+
"entries": {
|
|
5
|
+
"puppy-stride-tweens": {
|
|
6
|
+
"file": "puppy-stride-tweens-q5.bin.gz",
|
|
7
|
+
"width": 320,
|
|
8
|
+
"height": 320,
|
|
9
|
+
"frames": 799,
|
|
10
|
+
"uniqueFrames": 683,
|
|
11
|
+
"sourceSha256": "15e8ef49947cec4a1dcb3393d43a2ad48125d1bcd30f01275087c3df61627392",
|
|
12
|
+
"sourcePackedSha256": "439c8d235492ebb1e11cdb2f4cb1078b7840f14c0586c15544cb984d06d1047b",
|
|
13
|
+
"encodedBytes": 44585401,
|
|
14
|
+
"gzipBytes": 7564304,
|
|
15
|
+
"residentPixelBytes": 27752723,
|
|
16
|
+
"encodedSha256": "eecf92fd402843bef43aa4b154db6eba999959dd16cd8e34c54e42c88eaade10",
|
|
17
|
+
"quantizedSha256": "a74614dc210b245e5f8a4dba6a8cfb9b11b8da8dba9e2537fab53458ba27f02c"
|
|
18
|
+
},
|
|
19
|
+
"puppy-paper-rear-gallop": {
|
|
20
|
+
"file": "puppy-paper-rear-gallop-q5.bin.gz",
|
|
21
|
+
"width": 320,
|
|
22
|
+
"height": 320,
|
|
23
|
+
"frames": 162,
|
|
24
|
+
"uniqueFrames": 143,
|
|
25
|
+
"sourceSha256": "75972598be42314b92e64487106e3103ad477f897705dda869fc0b10cf68e256",
|
|
26
|
+
"sourcePackedSha256": "0c2d70643ef5807f1fa3e489abd65e0e9871041a8b45ea1027f94439601a3677",
|
|
27
|
+
"encodedBytes": 8770545,
|
|
28
|
+
"gzipBytes": 1468318,
|
|
29
|
+
"residentPixelBytes": 5456694,
|
|
30
|
+
"encodedSha256": "fe96e31d30348cc7d1fc674f40778d2312c9d1b40c57e634dcc397a35cc5ccf4",
|
|
31
|
+
"quantizedSha256": "a072f3a3f729f96556767b93d4921f76e32bc517aa06fb50f87fcb27fd05396c"
|
|
32
|
+
},
|
|
33
|
+
"puppy-paper-approach": {
|
|
34
|
+
"file": "puppy-paper-approach-q5.bin.gz",
|
|
35
|
+
"width": 320,
|
|
36
|
+
"height": 320,
|
|
37
|
+
"frames": 162,
|
|
38
|
+
"uniqueFrames": 139,
|
|
39
|
+
"sourceSha256": "f5558c57d5a445d396e06c060f9f8d64e6ce0ff5b9b92fa6d77ef9bb2984a2fe",
|
|
40
|
+
"sourcePackedSha256": "53bd77c5d06012b9b99884d2b38c499f0bcb9a42007736ef3d1cfffaba3c6ebf",
|
|
41
|
+
"encodedBytes": 7089140,
|
|
42
|
+
"gzipBytes": 1442754,
|
|
43
|
+
"residentPixelBytes": 4407560,
|
|
44
|
+
"encodedSha256": "6f57a5f506eabea41c00f02738c8124a4ae8e05471bdcd76e0a6e9ed739ca1a3",
|
|
45
|
+
"quantizedSha256": "c6e12fc09a7c314e65f7a115afb1e9cb865069cdd321c6f5483a92aa69517024"
|
|
46
|
+
},
|
|
47
|
+
"puppy-paper-seat": {
|
|
48
|
+
"file": "puppy-paper-seat-q5.bin.gz",
|
|
49
|
+
"width": 320,
|
|
50
|
+
"height": 320,
|
|
51
|
+
"frames": 51,
|
|
52
|
+
"uniqueFrames": 49,
|
|
53
|
+
"sourceSha256": "613dbeeeaec11804e80db0216922c8f62294745514ee6283bdce61a6d784dd5e",
|
|
54
|
+
"sourcePackedSha256": "2c34d1a34323e48e4ec73f60613ddacab9ff3814851275663fe573b00469e485",
|
|
55
|
+
"encodedBytes": 3326771,
|
|
56
|
+
"gzipBytes": 478093,
|
|
57
|
+
"residentPixelBytes": 2070312,
|
|
58
|
+
"encodedSha256": "b21aa11039b314ed3dec96818e571d54b6102bd0bc1f76e0a99ceb6d2b5ae097",
|
|
59
|
+
"quantizedSha256": "be0876275d124005ecb758b953f3a553a7f2748f5e3fd522612059f6fd81149a"
|
|
60
|
+
},
|
|
61
|
+
"puppy-paper-arrival-seat": {
|
|
62
|
+
"file": "puppy-paper-arrival-seat-q5.bin.gz",
|
|
63
|
+
"width": 320,
|
|
64
|
+
"height": 320,
|
|
65
|
+
"frames": 51,
|
|
66
|
+
"uniqueFrames": 49,
|
|
67
|
+
"sourceSha256": "13acb62fd573ff7ef97bcf59be80757897fe9d1784f187ab278990ff94a643b9",
|
|
68
|
+
"sourcePackedSha256": "014ee6e77802de49e9bcb77666867619b03688fd1a57040701904385a35dcd16",
|
|
69
|
+
"encodedBytes": 3332894,
|
|
70
|
+
"gzipBytes": 489164,
|
|
71
|
+
"residentPixelBytes": 2074316,
|
|
72
|
+
"encodedSha256": "3b2ef9e322e625340c42a549f17165492cc14f724f4593bf298f67195677bb6e",
|
|
73
|
+
"quantizedSha256": "77eb55a8922fda7f9a39c2b247eeb7098a3bacbf4c38d4652e7686650d9396aa"
|
|
74
|
+
},
|
|
75
|
+
"puppy-paper-behaviors": {
|
|
76
|
+
"file": "puppy-paper-behaviors-q5.bin.gz",
|
|
77
|
+
"width": 320,
|
|
78
|
+
"height": 320,
|
|
79
|
+
"frames": 162,
|
|
80
|
+
"uniqueFrames": 142,
|
|
81
|
+
"sourceSha256": "7918261fb64c57a91739729841fd84c6dd53891196c7fb76ee9c27712ab6ef5d",
|
|
82
|
+
"sourcePackedSha256": "7785ef65b8a2a5bf6f7ce600fe9957a60d9af82066ff49275bba061eac5392d1",
|
|
83
|
+
"encodedBytes": 7031343,
|
|
84
|
+
"gzipBytes": 1450156,
|
|
85
|
+
"residentPixelBytes": 4373034,
|
|
86
|
+
"encodedSha256": "38cfdfcee9c857c56a14f0a9734cb3301b4a04cb8e1ae3fb2e2b2ffe3666240f",
|
|
87
|
+
"quantizedSha256": "3c8f40416d2fff1c1031d3ad8917ea885998a786126d5973dfee4102893a0a53"
|
|
88
|
+
},
|
|
89
|
+
"puppy-paper-actions-v9": {
|
|
90
|
+
"file": "puppy-paper-actions-v9-q5.bin.gz",
|
|
91
|
+
"width": 480,
|
|
92
|
+
"height": 480,
|
|
93
|
+
"frames": 594,
|
|
94
|
+
"uniqueFrames": 474,
|
|
95
|
+
"sourceSha256": "1e0db7138d087292a3e70c246a1d56af590b3fb50928687a026e7080d7657c38",
|
|
96
|
+
"sourcePackedSha256": "ce5426d2fb9b2bb5d20b4f206215252954f9cc20d830d309a2d74ed441e37f02",
|
|
97
|
+
"encodedBytes": 24733003,
|
|
98
|
+
"gzipBytes": 4614142,
|
|
99
|
+
"residentPixelBytes": 15388998,
|
|
100
|
+
"encodedSha256": "615fb04961a38e592a661a20ad50fad45e1e4205e34198fa87a155ace966ea77",
|
|
101
|
+
"quantizedSha256": "fd1f23fe5dbd79bcf3cb9e060b9adfa0948cd4423e4b19e5810671e42ee952be"
|
|
102
|
+
},
|
|
103
|
+
"puppy-companion-interactions-v3": {
|
|
104
|
+
"file": "puppy-companion-interactions-v3-q5.bin.gz",
|
|
105
|
+
"width": 320,
|
|
106
|
+
"height": 320,
|
|
107
|
+
"frames": 360,
|
|
108
|
+
"uniqueFrames": 124,
|
|
109
|
+
"sourceSha256": "8438ee6cfc52b28f8e327bf37453c8e5ad7d568b2569cd4c5ed1e051d7026905",
|
|
110
|
+
"sourcePackedSha256": "deb8a3618451087fdae102f16ef7528c79c91b249844db1bfa9f9399c5355051",
|
|
111
|
+
"encodedBytes": 8023311,
|
|
112
|
+
"gzipBytes": 1150175,
|
|
113
|
+
"residentPixelBytes": 4992197,
|
|
114
|
+
"encodedSha256": "5ebfc58c9cfeaf349d30bc65be2e4663f7a3b8be9f35ca5d6da323172624de7a",
|
|
115
|
+
"quantizedSha256": "ebf86e2671234feb46a0933bb9c6d367c353d1b38a5bbf01e07c7b7f6183c1ea"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
package/puppy-clean.mjs
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {stableAt,groundOffset,createStableZoomies} from './puppy-stable.mjs';
|
|
2
|
+
import {createFaceMotion} from './puppy-face.mjs';
|
|
3
|
+
import {grayFrameReader,isGrayFrameSource} from './puppy-frame-store.mjs';
|
|
4
|
+
export const CLEAN_BYTES=47*17*320*320;
|
|
5
|
+
export const STRIDE_TEMPO=.72;
|
|
6
|
+
export function retimeRun(phase,knots){
|
|
7
|
+
if(!knots)return phase;
|
|
8
|
+
const count=knots.length-1;
|
|
9
|
+
if(count<2||count>20||knots[0]!==0||knots[count]!==20||knots.some((x,i)=>!Number.isFinite(x)||(i&&x<=knots[i-1])))throw Error('Invalid gait timing');
|
|
10
|
+
const tangent=i=>{i%=count;const before=i?knots[i]-knots[i-1]:20-knots[count-1],after=knots[i+1]-knots[i],w1=2*after+before,w2=after+2*before;return (w1+w2)/(w1*before+w2*after);};
|
|
11
|
+
let index=0;while(index<count-1&&phase>knots[index+1])index++;
|
|
12
|
+
const h=knots[index+1]-knots[index],p=Math.max(0,Math.min(1,(phase-knots[index])/h)),p2=p*p,p3=p2*p;
|
|
13
|
+
return (2*p3-3*p2+1)*index+(p3-2*p2+p)*h*tangent(index)+(-2*p3+3*p2)*(index+1)+(p3-p2)*h*tangent(index+1);
|
|
14
|
+
}
|
|
15
|
+
export function cleanAt(seconds,options={}){
|
|
16
|
+
const state=stableAt(seconds,{...options,tempo:options.tempo??(options.sequence?STRIDE_TEMPO:.6),quickLaunch:options.quickLaunch??!!options.sequence,easedTurns:true,rampRest:true});
|
|
17
|
+
if(state.state==='run'){
|
|
18
|
+
const phase=retimeRun(state.pair+state.blend,options.timing),index=Math.floor(phase),count=options.sequence?.length??20;
|
|
19
|
+
state.pair=index%count;state.pose=options.sequence?.[state.pair]??state.pair;state.blend=phase-index;
|
|
20
|
+
}
|
|
21
|
+
return state;
|
|
22
|
+
}
|
|
23
|
+
export function cleanGroundOffset(state,meta){
|
|
24
|
+
if(state.state==='run'&&meta.run_sequence){
|
|
25
|
+
const seq=meta.run_sequence,n=seq.length,i=state.pair,p=state.blend,v=meta.ground_offsets;
|
|
26
|
+
const a=v[seq[(i+n-1)%n]],b=v[seq[i]],c=v[seq[(i+1)%n]],d=v[seq[(i+2)%n]];
|
|
27
|
+
return .5*(2*b+(-a+c)*p+(2*a-5*b+4*c-d)*p*p+(-a+3*b-3*c+d)*p*p*p);
|
|
28
|
+
}
|
|
29
|
+
if(state.pair<30||state.pair>40)return groundOffset(state,meta);
|
|
30
|
+
const i=state.pair,p=state.blend,v=meta.ground_offsets;
|
|
31
|
+
const a=v[Math.max(30,i-1)],b=v[i],c=v[i+1],d=v[Math.min(41,i+2)];
|
|
32
|
+
return .5*(2*b+(-a+c)*p+(2*a-5*b+4*c-d)*p*p+(-a+3*b-3*c+d)*p*p*p);
|
|
33
|
+
}
|
|
34
|
+
export function createCachedTween(cache,info){
|
|
35
|
+
if(!isGrayFrameSource(cache)||cache.byteLength!==CLEAN_BYTES||info.pairs!==47||info.samples!==17||info.width!==320||info.height!==320||info.channels!==1||info.bytes!==CLEAN_BYTES)throw Error('Invalid baked tween cache');
|
|
36
|
+
const frames=grayFrameReader(cache,320,320,47*17),output=new Uint8ClampedArray(320*320*4),stride=320*320;
|
|
37
|
+
for(let i=3;i<output.length;i+=4)output[i]=255;
|
|
38
|
+
return state=>{
|
|
39
|
+
if(!Number.isInteger(state.pair)||state.pair<0||state.pair>=47||!Number.isFinite(state.blend))throw Error('Invalid baked tween state');
|
|
40
|
+
const phase=Math.max(0,Math.min(1,state.blend))*16,index=Math.min(15,Math.floor(phase)),alpha=phase-index;
|
|
41
|
+
const a=frames.getFrame(state.pair*17+index),b=frames.getFrame(state.pair*17+index+1);
|
|
42
|
+
for(let i=0,j=0;i<stride;i++,j+=4){const value=a[i]*(1-alpha)+b[i]*alpha;output[j]=output[j+1]=output[j+2]=value;}
|
|
43
|
+
return output;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function createCleanZoomies(atlas,cache,meta,cacheInfo,width,height,{secondaryMotion=true,quickLaunch=!!cacheInfo.run_sequence,sampleState=cleanAt,frameTransform,groundAt=cleanGroundOffset}={}){
|
|
47
|
+
const renderMeta=cacheInfo.pair_map?{...meta,pairs:cacheInfo.pair_map,run_sequence:cacheInfo.run_sequence}:meta;
|
|
48
|
+
if(cacheInfo.run_sequence){const seq=cacheInfo.run_sequence;if(seq.some((v,i)=>!Number.isInteger(v)||v<0||v>=20||renderMeta.pairs[i][0]!==v||renderMeta.pairs[i][1]!==seq[(i+1)%seq.length]))throw Error('Invalid curated gait');}
|
|
49
|
+
const tween=createCachedTween(cache,cacheInfo),face=secondaryMotion&&cacheInfo.run_sequence?createFaceMotion():null;
|
|
50
|
+
return createStableZoomies(atlas,null,renderMeta,width,height,{sampleState:(s,o)=>sampleState(s,{...o,quickLaunch,timing:cacheInfo.run_timing,sequence:cacheInfo.run_sequence}),frameProvider:state=>{const image=tween(state),moved=face?face(image,state):image;return frameTransform?frameTransform(moved,state):moved;},groundAt});
|
|
51
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"width":320,"height":320,"samples":9,"pairs":40,"bytes":36864000,"sha256":"8438ee6cfc52b28f8e327bf37453c8e5ad7d568b2569cd4c5ed1e051d7026905","clips":{"treat-eat":[30,31,32,33,34,35,36,37,38,39],"ball-pickup":[13,14,15,16,17,18,19,20,21,22],"ball-drop":[23,24,25,26,27,28,29]},"edges":[[0,2],[2,3],[3,4],[4,5],[5,4],[5,6],[6,0],[0,7],[7,8],[8,9],[9,10],[10,11],[11,0],[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9],[9,10],[10,11],[11,12],[12,13],[13,14],[14,15],[15,16],[16,0]],"ballSourceKeys":{"13":[0,1],"14":[1,2],"15":[2,3],"16":[3,4],"17":[4,5],"18":[5,6],"19":[6,7],"20":[7,8],"21":[8,9],"22":[9,10],"23":[10,11],"24":[11,12],"25":[12,13],"26":[13,14],"27":[14,15],"28":[15,16],"29":[16,0]},"sourceSequences":{"ball-pickup":[0,1,2,3,4,5,6,7,8,9,10],"ball-drop":[10,11,12,13,14,15,16,0]},"scale":0.7870722433460076,"registration":[{"cell":0,"matrix":[[0.7870722433460076,0.0,13.04942965779469],[0.0,0.7870722433460076,75.68441064638785]]},{"cell":1,"matrix":[[0.7870722433460076,0.0,-232.12357414448667],[0.0,0.7870722433460076,75.68441064638785]]},{"cell":2,"matrix":[[0.7870722433460076,0.0,-475.32889733840295],[0.0,0.7870722433460076,75.68441064638785]]},{"cell":3,"matrix":[[0.7870722433460076,0.0,-718.5342205323193],[0.0,0.7870722433460076,74.89733840304183]]},{"cell":4,"matrix":[[0.7870722433460076,0.0,10.688212927756666],[0.0,0.7870722433460076,-162.01140684410643]]},{"cell":5,"matrix":[[0.7870722433460076,0.0,-232.12357414448667],[0.0,0.7870722433460076,-162.01140684410643]]},{"cell":6,"matrix":[[0.7870722433460076,0.0,-476.115969581749],[0.0,0.7870722433460076,-162.01140684410643]]},{"cell":7,"matrix":[[0.7870722433460076,0.0,-718.9277566539923],[0.0,0.7870722433460076,-162.01140684410643]]},{"cell":8,"matrix":[[0.7870722433460076,0.0,12.655893536121681],[0.0,0.7870722433460076,-407.57794676806077]]},{"cell":9,"matrix":[[0.7870722433460076,0.0,-231.7300380228137],[0.0,0.7870722433460076,-407.57794676806077]]},{"cell":10,"matrix":[[0.7870722433460076,0.0,-474.93536121673003],[0.0,0.7870722433460076,-407.57794676806077]]},{"cell":11,"matrix":[[0.7870722433460076,0.0,-718.5342205323193],[0.0,0.7870722433460076,-407.57794676806077]]},{"cell":12,"matrix":[[0.7870722433460076,0.0,12.262357414448672],[0.0,0.7870722433460076,-647.6349809885932]]},{"cell":13,"matrix":[[0.7870722433460076,0.0,-232.12357414448667],[0.0,0.7870722433460076,-646.8479087452471]]},{"cell":14,"matrix":[[0.7870722433460076,0.0,-474.14828897338396],[0.0,0.7870722433460076,-647.6349809885932]]},{"cell":15,"matrix":[[0.7870722433460076,0.0,-718.9277566539923],[0.0,0.7870722433460076,-647.6349809885932]]}],"neutralSha256":"0b0584bd032ddf41d62f02c5064547d667e84eea9b8a74e3ff2d7043abb5eb78","sourceHashes":{"puppy-companion-interactions-v2.bin.gz":"75d682c0eaab31dd01038f36fd6da425eaee6cb92afc8857e06e3013e3307724","puppy-interactions12-v1-sheet.png":"e3931afbd935355734f9448f12495edb269547cadba30dcd36265ea9e4cf7afd","puppy-paper-seat.bin.gz":"a863225bef502fa3d60fe97c85007a9e85b818d53e5c3b5490fddd80b0c100d9","prepare-companion-interactions-v3.py":"d0d195683d2869f9bf5a94e8c8195d00cb5caf3caa4099c49cc20e384592da73"},"method":"v2 ball sprites byte-exact; treat is full original generated sprite, one source scale, no head/torso mask and no ghost-frame morph","treatSourceKeys":{"30":[0,1],"31":[1,2],"32":[2,3],"33":[3,4],"34":[4,5],"35":[5,4],"36":[4,5],"37":[5,6],"38":[6,1],"39":[1,0]},"treatKeyHashes":["0b0584bd032ddf41d62f02c5064547d667e84eea9b8a74e3ff2d7043abb5eb78","0870c83bbd95da39680c4297fb2a7c08fafb296578f7e872de31ace3736e303d","fe95b5930e429cb1e42ca5c6c06e500c4c30446164ece075fd580d85f8a014e0","2533e5d855f56867c2d0650da1644a175e414145c03a29e43281996094e14e67","a75805e1a40004160a07275db03cc74310950bb8200ca6ca71566706e6a8d776","51b81c3433ba2ee74127a39386bf725d654c72bffbf6cfcbe475107cf1d13cdb","d11f159c000b2e432a77dd3d922d7f51435db5f2a9799f55290d3dedc9c88636"],"treatScale":0.6124260355029586,"treatRegistration":[{"cell":0,"matrix":[[0.6124260355029586,0.0,36.39497041420118],[0.0,0.6124260355029586,57.47928994082841]]},{"cell":1,"matrix":[[0.6124260355029586,0.0,-149.47633136094674],[0.0,0.6124260355029586,56.25443786982248]]},{"cell":2,"matrix":[[0.6124260355029586,0.0,-335.3476331360947],[0.0,0.6124260355029586,56.86686390532543]]},{"cell":3,"matrix":[[0.6124260355029586,0.0,-521.8313609467456],[0.0,0.6124260355029586,56.25443786982248]]},{"cell":4,"matrix":[[0.6124260355029586,0.0,37.00739644970413],[0.0,0.6124260355029586,-181.36686390532543]]},{"cell":5,"matrix":[[0.6124260355029586,0.0,-148.8639053254438],[0.0,0.6124260355029586,-181.36686390532543]]}]}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Autonomous companion "life" controller layered over a paper puppy actor.
|
|
2
|
+
// The parent calls actor.update(dt) THEN life.update(dt). Commands are only issued
|
|
3
|
+
// while the actor rests at a shared safe endpoint (idle/down); everything else waits.
|
|
4
|
+
// Exception: an accepted ball throw reacts at once via actor.chase (the actor owns safe
|
|
5
|
+
// interruption); actors without chase fall back to go at the next safe endpoint.
|
|
6
|
+
// Parameters are authored for feel, not canine science.
|
|
7
|
+
|
|
8
|
+
const SAFE=new Set(['idle','down']);
|
|
9
|
+
const HOME={x:0,z:.2};
|
|
10
|
+
const BALL_TARGET={x:0,z:-4};
|
|
11
|
+
const OFFER={x:0,z:.3};
|
|
12
|
+
// Hand-fed treat marker, relative to the puppy's current root (no travel for treats).
|
|
13
|
+
const TREAT_OFFSET={z:.08,height:.25};
|
|
14
|
+
const COOLDOWN={ball:6,treat:15};
|
|
15
|
+
const FLIGHT=.65,BALL_PEAK=.75,CARRY_HEIGHT=.19,SETTLE_FALLBACK=.6,MAX_DT=.25,ARRIVE=.05;
|
|
16
|
+
const LABEL={
|
|
17
|
+
start:'기다리는 중',pause:'잠시 느긋하게 둘러보는 중',lie:'엎드리는 중',rest:'엎드려 쉬는 중',recover:'앉아서 기운 차리는 중',
|
|
18
|
+
sit:'앉는 중',watch:'앉아서 지켜보는 중',look:'고개를 돌려 살피는 중',observe:'가만히 주변 관찰 중',
|
|
19
|
+
stroll:'옆으로 살짝 걸어가는 중',sniff:'잠깐 멈춰 주변을 살피는 중',dash:'저 멀리 달려가는 중',far:'멀리서 둘러보는 중',home:'제자리로 돌아오는 중',
|
|
20
|
+
fetch:'공을 쫓아가는 중',pickup:'공을 무는 중',carry:'공을 물고 돌아오는 중',drop:'공을 내려놓는 중',offer:'공을 내려놓고 기다리는 중',
|
|
21
|
+
treatSit:'간식 앞에 앉는 중',chew:'간식 먹는 중'
|
|
22
|
+
};
|
|
23
|
+
const PENDING_LABEL={treat:'곧 간식'};
|
|
24
|
+
// Baked interaction clips, played only while holding at the shared seated endpoint.
|
|
25
|
+
const GESTURE={'ball-pickup':1.4,'ball-drop':1.2,'treat-eat':2.4};
|
|
26
|
+
const clamp=(v,a,b)=>Math.min(b,Math.max(a,v));
|
|
27
|
+
|
|
28
|
+
function mulberry32(seed){
|
|
29
|
+
let a=seed>>>0;
|
|
30
|
+
return()=>{a=a+0x6d2b79f5>>>0;let t=a;t=Math.imul(t^t>>>15,t|1);t^=t+Math.imul(t^t>>>7,t|61);return((t^t>>>14)>>>0)/4294967296;};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function createCompanionLife(actor,{seed=731,energy=.8}={}){
|
|
34
|
+
for(const name of ['update','sample','go','come','sit','lie','look','walk','roll','rest'])
|
|
35
|
+
if(!actor||typeof actor[name]!=='function')throw TypeError(`actor.${name} must be a function`);
|
|
36
|
+
if(!Number.isInteger(seed))throw TypeError('seed must be an integer');
|
|
37
|
+
if(!Number.isFinite(energy)||energy<0||energy>1)throw RangeError('energy must be within 0..1');
|
|
38
|
+
|
|
39
|
+
const rand=mulberry32(seed),range=(a,b)=>a+(b-a)*rand(),side=()=>rand()<.5?'left':'right';
|
|
40
|
+
const needs={energy,social:.5,curiosity:.5};
|
|
41
|
+
const cooldowns={ball:0,treat:0};
|
|
42
|
+
let clock=0,decisions=0,lastEpisode=null;
|
|
43
|
+
let queue=[],hold=0,holdIntent=null,waiting=null,gesture=null;
|
|
44
|
+
let intent='start',label=LABEL.start,pending=null,active=null,ball=null,treat=null;
|
|
45
|
+
|
|
46
|
+
const cmd=(name,args,step,when)=>({cmd:name,args,intent:step,label:LABEL[step],when});
|
|
47
|
+
const wait=(seconds,step)=>({hold:seconds,intent:step,label:LABEL[step]});
|
|
48
|
+
const play=(clip,step)=>({hold:GESTURE[clip],gesture:clip,intent:step,label:LABEL[step]});
|
|
49
|
+
// Skip sit() when the actor already rests in the canonical front-seated endpoint.
|
|
50
|
+
const unseated=()=>{const s=actor.sample(clock);return !(actor.state==='idle'&&s.seatProgress===1&&s.view==='approach'&&(s.seatVariant??'default')==='default');};
|
|
51
|
+
// Treats accept any seat variant at the front-seated endpoint: the hand comes to the puppy.
|
|
52
|
+
const seatedAnyVariant=()=>{const s=actor.sample(clock);return actor.state==='idle'&&s.seatProgress===1&&s.view==='approach';};
|
|
53
|
+
const fx=fn=>({fx:fn});
|
|
54
|
+
const home=()=>cmd('go',[HOME.x,HOME.z],'home');
|
|
55
|
+
|
|
56
|
+
// Each episode is a short coherent plan; a pause always leads in so autonomy never stalls.
|
|
57
|
+
const EPISODES={
|
|
58
|
+
rest:()=>[cmd('lie',[],'lie'),wait(range(10,18),'rest'),cmd('sit',[],'recover'),wait(range(3,6),'recover')],
|
|
59
|
+
watch:()=>[cmd('sit',[],'sit'),cmd('look',[side()],'look'),wait(range(3,9),'watch'),fx(()=>{needs.social-=.3;needs.curiosity+=.1;})],
|
|
60
|
+
observe:()=>[cmd('look',[side()],'look'),wait(range(3,9),'observe'),fx(()=>{needs.curiosity-=.15;})],
|
|
61
|
+
stroll:()=>[cmd('walk',[side(),range(.08,.18)],'stroll'),wait(range(2,4),'sniff'),home(),fx(()=>{needs.energy-=.08;needs.curiosity-=.2;})],
|
|
62
|
+
dash:()=>[cmd('go',[(rand()*2-1)*.18,-range(3,8)],'dash'),wait(range(1.5,3),'far'),home(),fx(()=>{needs.energy-=.3;needs.curiosity-=.4;})]
|
|
63
|
+
};
|
|
64
|
+
const weights=()=>{
|
|
65
|
+
const {energy:e,social:s,curiosity:c}=needs;
|
|
66
|
+
return {rest:e<.35?6:(1-e)*1.2,watch:.8+s,observe:.6+c*.6,stroll:1.2*c*e,dash:e>.55?1.2*e*c:0};
|
|
67
|
+
};
|
|
68
|
+
function decide(){
|
|
69
|
+
const w=weights();if(lastEpisode)w[lastEpisode]=0;
|
|
70
|
+
const kinds=Object.keys(w),total=kinds.reduce((sum,k)=>sum+w[k],0);
|
|
71
|
+
let pick=rand()*total,kind=kinds.find(k=>(pick-=w[k])<0)??'observe';
|
|
72
|
+
lastEpisode=kind;decisions++;
|
|
73
|
+
queue=[wait(range(3,9),'pause'),...EPISODES[kind]()];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const landed=()=>ball?.mode==='flight'&&clock-ball.start>=FLIGHT;
|
|
77
|
+
const arrived=()=>{const s=actor.sample(clock);return SAFE.has(actor.state)&&Math.hypot(s.x-BALL_TARGET.x,s.z-BALL_TARGET.z)<ARRIVE;};
|
|
78
|
+
// The leading go is dropped when interact() already dispatched the chase; pickup waits for both arrival and landing.
|
|
79
|
+
const BALL_STEPS=()=>[
|
|
80
|
+
cmd('go',[BALL_TARGET.x,BALL_TARGET.z],'fetch'),{until:()=>landed()&&arrived()},
|
|
81
|
+
fx(()=>{ball={mode:'ground',x:BALL_TARGET.x,z:BALL_TARGET.z};}),
|
|
82
|
+
cmd('sit',[],'pickup'),play('ball-pickup','pickup'),fx(()=>{ball={mode:'carried'};}),cmd('go',[HOME.x,HOME.z],'carry'),
|
|
83
|
+
cmd('sit',[],'drop',unseated),play('ball-drop','drop'),
|
|
84
|
+
fx(()=>{ball={mode:'ground',x:OFFER.x,z:OFFER.z};needs.social-=.4;}),wait(3,'offer'),fx(()=>{ball=null;})
|
|
85
|
+
];
|
|
86
|
+
// Hand-feed where the puppy already is: sit only if not front-seated, never go/walk/chase/come.
|
|
87
|
+
const TREAT_STEPS=()=>[
|
|
88
|
+
fx(()=>{treat=true;}),cmd('sit',[],'treatSit',()=>!seatedAnyVariant()),
|
|
89
|
+
play('treat-eat','chew'),fx(()=>{treat=null;needs.energy+=.25;needs.social-=.3;})
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
function startInteraction(){
|
|
93
|
+
active=pending;pending=null;decisions++;hold=0;
|
|
94
|
+
queue=active==='ball'?BALL_STEPS():TREAT_STEPS();
|
|
95
|
+
}
|
|
96
|
+
function finishInteraction(){cooldowns[active]=COOLDOWN[active];active=null;}
|
|
97
|
+
|
|
98
|
+
function drift(dt){
|
|
99
|
+
const resting=holdIntent==='rest'||holdIntent==='recover';
|
|
100
|
+
needs.energy+=resting?.04*dt:-.004*dt;
|
|
101
|
+
if(!active){needs.curiosity+=.01*dt;needs.social+=.008*dt;}
|
|
102
|
+
for(const k in needs)needs[k]=clamp(needs[k],0,1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function update(dt){
|
|
106
|
+
if(typeof dt!=='number'||!Number.isFinite(dt)||dt<0)throw RangeError('dt must be a finite non-negative number');
|
|
107
|
+
dt=Math.min(dt,MAX_DT);clock+=dt;
|
|
108
|
+
for(const k in cooldowns)cooldowns[k]=Math.max(0,cooldowns[k]-dt);
|
|
109
|
+
drift(dt);
|
|
110
|
+
const safe=SAFE.has(actor.state);
|
|
111
|
+
if(waiting){
|
|
112
|
+
waiting.age+=dt;if(!safe)waiting.left=true;
|
|
113
|
+
if(!safe||(!waiting.left&&waiting.age<SETTLE_FALLBACK))return;
|
|
114
|
+
waiting=null;
|
|
115
|
+
}
|
|
116
|
+
if(hold>0){
|
|
117
|
+
hold-=dt;if(gesture)gesture.elapsed+=dt;
|
|
118
|
+
if(pending&&!active&&safe)hold=0;
|
|
119
|
+
if(hold>0)return;
|
|
120
|
+
}
|
|
121
|
+
holdIntent=null;gesture=null;
|
|
122
|
+
if(!safe)return;
|
|
123
|
+
if(pending&&!active)startInteraction();
|
|
124
|
+
// Run instant effects; stop at the first hold or issued command (at most one command per update).
|
|
125
|
+
for(;;){
|
|
126
|
+
if(!queue.length){
|
|
127
|
+
if(active){finishInteraction();if(pending)startInteraction();else decide();}
|
|
128
|
+
else decide();
|
|
129
|
+
}
|
|
130
|
+
const step=queue.shift();
|
|
131
|
+
if(step.fx){step.fx();for(const k in needs)needs[k]=clamp(needs[k],0,1);continue;}
|
|
132
|
+
if(step.until){if(step.until())continue;queue.unshift(step);return;}
|
|
133
|
+
if(step.when&&!step.when())continue;
|
|
134
|
+
intent=step.intent;label=step.label;
|
|
135
|
+
if(step.hold!==undefined){hold=step.hold;holdIntent=step.intent;if(step.gesture)gesture={clip:step.gesture,duration:step.hold,elapsed:0};return;}
|
|
136
|
+
if(actor[step.cmd](...step.args)!==false)waiting={age:0,left:false};
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function interact(kind){
|
|
142
|
+
if(kind!=='ball'&&kind!=='treat')return false;
|
|
143
|
+
if(pending||active||cooldowns[kind]>0)return false;
|
|
144
|
+
if(kind==='treat'){pending=kind;return true;}
|
|
145
|
+
// Ball: launch now and drop obsolete controller plans; the actor's own state is left to chase.
|
|
146
|
+
active='ball';decisions++;ball={mode:'flight',start:clock};
|
|
147
|
+
queue=BALL_STEPS();hold=0;holdIntent=null;gesture=null;waiting=null;
|
|
148
|
+
intent='fetch';label=LABEL.fetch;
|
|
149
|
+
const urgent=typeof actor.chase==='function';
|
|
150
|
+
if((urgent||SAFE.has(actor.state))&&actor[urgent?'chase':'go'](BALL_TARGET.x,BALL_TARGET.z)!==false)queue.shift();
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Recomputed from the live pose so the marker stays truthful before and after sitting.
|
|
155
|
+
function treatReport(){
|
|
156
|
+
if(!treat)return null;
|
|
157
|
+
const s=actor.sample(clock);return {x:s.x,z:s.z+TREAT_OFFSET.z,height:TREAT_OFFSET.height};
|
|
158
|
+
}
|
|
159
|
+
function ballReport(){
|
|
160
|
+
if(!ball)return null;
|
|
161
|
+
if(ball.mode==='flight'){
|
|
162
|
+
const p=clamp((clock-ball.start)/FLIGHT,0,1);
|
|
163
|
+
if(p===1)return {x:BALL_TARGET.x,z:BALL_TARGET.z,height:0,carried:false};
|
|
164
|
+
return {x:HOME.x+(BALL_TARGET.x-HOME.x)*p,z:HOME.z+(BALL_TARGET.z-HOME.z)*p,height:4*BALL_PEAK*p*(1-p),carried:false};
|
|
165
|
+
}
|
|
166
|
+
if(ball.mode==='carried'){const s=actor.sample(clock);return {x:s.x,z:s.z,height:CARRY_HEIGHT,carried:true};}
|
|
167
|
+
return {x:ball.x,z:ball.z,height:0,carried:false};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
update,interact,
|
|
172
|
+
get report(){
|
|
173
|
+
const interaction=active??pending;
|
|
174
|
+
return {
|
|
175
|
+
intent,label:pending?`${label} · ${PENDING_LABEL[pending]}`:label,interaction,busy:interaction!==null,
|
|
176
|
+
ball:ballReport(),treat:treatReport(),energy:needs.energy,decisions,cooldowns:{...cooldowns},
|
|
177
|
+
// Local hold clock only: progress freezes between updates; null outside the stationary hold.
|
|
178
|
+
gesture:gesture&&SAFE.has(actor.state)?{clip:gesture.clip,progress:clamp(gesture.elapsed/gesture.duration,0,1)}:null
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Small physical toys in the SAME fixed camera as the puppy, before Braille
|
|
2
|
+
// conversion. No minimum thumbnail size, DOM overlay, sprite zoom or new dog art.
|
|
3
|
+
// mouth: renderer.lastMouth for the frame just painted. A carried ball sits on that
|
|
4
|
+
// measured drawn mouth only; without one (side/rear/unmeasured pose) it is hidden.
|
|
5
|
+
export function paintCompanionObjects(pixels,width,height,projection,report,state,mouth=null){
|
|
6
|
+
const objects=[];
|
|
7
|
+
// Interaction drawings already include the toy/food. Never paint a second
|
|
8
|
+
// floating ball over the baked mouth, or a biscuit through the puppy's chest.
|
|
9
|
+
if(report.gesture)return pixels;
|
|
10
|
+
if(report.ball?.carried){if(mouth&&[mouth.x,mouth.y,mouth.rx,mouth.ry].every(Number.isFinite)&&mouth.rx>0&&mouth.ry>0)objects.push({kind:'ball',screen:mouth});}
|
|
11
|
+
else if(report.ball)objects.push({...report.ball,radius:.035,kind:'ball'});
|
|
12
|
+
if(report.treat)objects.push({...report.treat,height:report.treat.height??.018,radius:.022,kind:'treat'});
|
|
13
|
+
for(const o of objects){
|
|
14
|
+
let cx,cy,rx,ry;
|
|
15
|
+
if(o.screen)({x:cx,y:cy,rx,ry}=o.screen);
|
|
16
|
+
else{
|
|
17
|
+
const p=projection.project(o.x,o.height??0,o.z),edge=projection.project(o.x+o.radius,o.height??0,o.z);
|
|
18
|
+
cx=p.x*width;cy=p.y*height;rx=Math.abs(edge.x-p.x)*width;
|
|
19
|
+
const up=projection.project(o.x,(o.height??0)+o.radius,o.z);ry=Math.abs(up.y-p.y)*height;
|
|
20
|
+
}
|
|
21
|
+
if(![cx,cy,rx,ry].every(Number.isFinite)||rx<=0||ry<=0)continue;
|
|
22
|
+
for(let y=Math.max(0,Math.floor(cy-ry));y<Math.min(height,Math.ceil(cy+ry));y++)
|
|
23
|
+
for(let x=Math.max(0,Math.floor(cx-rx));x<Math.min(width,Math.ceil(cx+rx));x++){
|
|
24
|
+
const u=(x+.5-cx)/rx,v=(y+.5-cy)/ry;if(u*u+v*v>1)continue;
|
|
25
|
+
const tone=o.kind==='treat'?((x+y)%3?190:85):Math.abs(v+.25*u)<.18?85:225;
|
|
26
|
+
const j=(y*width+x)*4;pixels[j]=pixels[j+1]=pixels[j+2]=tone;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return pixels;
|
|
30
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {grayFrameReader,isGrayFrameSource} from './puppy-frame-store.mjs';
|
|
2
|
+
// Prebaked interaction samples; the original seat is the exact shared endpoint.
|
|
3
|
+
// Pure sampling, no live image morph, root motion, camera or pose-size fitting.
|
|
4
|
+
export function createCompanionSpriteSampler(bytes,info){
|
|
5
|
+
const n=320*320;
|
|
6
|
+
if(!isGrayFrameSource(bytes)||info?.width!==320||info.height!==320||info.samples!==9||!Number.isInteger(info.pairs)||info.pairs<1||info.pairs>128||bytes.byteLength!==info.pairs*9*n)throw Error('Invalid companion sprite cache');
|
|
7
|
+
for(const key of ['treat-eat','ball-pickup','ball-drop'])if(!Array.isArray(info.clips?.[key])||!info.clips[key].length||!info.clips[key].every(p=>Number.isInteger(p)&&p>=0&&p<info.pairs))throw Error('Invalid companion sprite clip');
|
|
8
|
+
const frames=grayFrameReader(bytes,320,320,info.pairs*9),rgba=new Uint8ClampedArray(n*4);for(let i=3;i<rgba.length;i+=4)rgba[i]=255;
|
|
9
|
+
return({clip,progress})=>{
|
|
10
|
+
const list=info.clips[clip];if(!list||!Number.isFinite(progress)||progress<0||progress>1)throw Error('Invalid companion sprite pose');
|
|
11
|
+
const q=progress*list.length,index=Math.min(list.length-1,Math.floor(q)),s=Math.round((q-index)*8),frame=frames.getFrame(list[index]*9+s);
|
|
12
|
+
for(let i=0,j=0;i<n;i++,j+=4)rgba[j]=rgba[j+1]=rgba[j+2]=frame[i];return rgba;
|
|
13
|
+
};
|
|
14
|
+
}
|