@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.
Files changed (297) hide show
  1. package/ASSET-PROVENANCE.md +43 -0
  2. package/ASSETS-LICENSE.md +58 -0
  3. package/ATTRIBUTION.md +54 -0
  4. package/EMBEDDING.md +96 -0
  5. package/INSTALLING.md +126 -0
  6. package/LICENSE +16 -0
  7. package/LICENSE-CODE +21 -0
  8. package/PLUGIN.md +110 -0
  9. package/PUPPY-MEMORY.md +57 -0
  10. package/PUPPY-Q5-COMPARISON.md +73 -0
  11. package/README.md +86 -2
  12. package/RELEASING.md +70 -0
  13. package/THIRD-PARTY-NOTICES.md +17 -0
  14. package/TRADEMARKS.md +21 -0
  15. package/WINDOWS-COMPANION.md +113 -0
  16. package/braille.mjs +45 -0
  17. package/examples/bridge.py +62 -0
  18. package/examples/embed.mjs +15 -0
  19. package/examples/live.mjs +40 -0
  20. package/examples/plugin.mjs +21 -0
  21. package/integrations/opencode/runtime.mjs +195 -0
  22. package/integrations/opencode/tui.tsx +59 -0
  23. package/integrations/windows-overlay/Overlay.cs +259 -0
  24. package/integrations/windows-overlay/desktop.mjs +87 -0
  25. package/integrations/windows-overlay/protocol.mjs +39 -0
  26. package/integrations/windows-overlay/worker.mjs +60 -0
  27. package/locomotion-core.mjs +21 -0
  28. package/locomotion-puppy.animal +0 -0
  29. package/package.json +131 -4
  30. package/pet-q5-manifest.json +118 -0
  31. package/puppy-clean.mjs +51 -0
  32. package/puppy-companion-interactions-v3-q5.bin.gz +0 -0
  33. package/puppy-companion-interactions-v3.json +1 -0
  34. package/puppy-companion-life.mjs +182 -0
  35. package/puppy-companion-objects.mjs +30 -0
  36. package/puppy-companion-sprites.mjs +14 -0
  37. package/puppy-continuous.mjs +57 -0
  38. package/puppy-face.mjs +46 -0
  39. package/puppy-frame-predictive.mjs +147 -0
  40. package/puppy-frame-store.mjs +108 -0
  41. package/puppy-mouth-anchor.json +1 -0
  42. package/puppy-mouth-anchor.mjs +33 -0
  43. package/puppy-paper-actions-v9-q5.bin.gz +0 -0
  44. package/puppy-paper-actions-v9.json +1 -0
  45. package/puppy-paper-actions.mjs +48 -0
  46. package/puppy-paper-approach-q5.bin.gz +0 -0
  47. package/puppy-paper-approach.json +1 -0
  48. package/puppy-paper-area.mjs +15 -0
  49. package/puppy-paper-arrival-seat-q5.bin.gz +0 -0
  50. package/puppy-paper-arrival-seat.json +1 -0
  51. package/puppy-paper-behaviors-q5.bin.gz +0 -0
  52. package/puppy-paper-behaviors.json +1 -0
  53. package/puppy-paper-behaviors.mjs +8 -0
  54. package/puppy-paper-contact.mjs +103 -0
  55. package/puppy-paper-director.mjs +21 -0
  56. package/puppy-paper-paw-transport.mjs +76 -0
  57. package/puppy-paper-rear-gallop-q5.bin.gz +0 -0
  58. package/puppy-paper-rear-gallop.json +1 -0
  59. package/puppy-paper-seat-q5.bin.gz +0 -0
  60. package/puppy-paper-seat.json +14 -0
  61. package/puppy-paper-seat.mjs +13 -0
  62. package/puppy-paper-trick-timing.mjs +58 -0
  63. package/puppy-paper-world.mjs +108 -0
  64. package/puppy-paper.mjs +271 -0
  65. package/puppy-stable-meta.json +1606 -0
  66. package/puppy-stable.mjs +72 -0
  67. package/puppy-stride-meta.json +343 -0
  68. package/puppy-stride-tweens-q5.bin.gz +0 -0
  69. package/puppy-zoomies.mjs +27 -0
  70. package/puppy-zoomies30.mjs +12 -0
  71. package/retrieviewer-cli.mjs +94 -0
  72. package/retrieviewer-config.mjs +49 -0
  73. package/retrieviewer-install.mjs +157 -0
  74. package/retrieviewer-plugin.d.mts +44 -0
  75. package/retrieviewer-plugin.mjs +97 -0
  76. package/retrieviewer-stdio.mjs +38 -0
  77. package/retrieviewer.d.mts +85 -0
  78. package/retrieviewer.mjs +142 -0
  79. package/vendor/procedural-animals/LICENSE +21 -0
  80. package/vendor/procedural-animals/package.json +40 -0
  81. package/vendor/procedural-animals/src/animal.js +146 -0
  82. package/vendor/procedural-animals/src/bake.js +51 -0
  83. package/vendor/procedural-animals/src/build.js +81 -0
  84. package/vendor/procedural-animals/src/core/build/coatKit.js +121 -0
  85. package/vendor/procedural-animals/src/core/build/featherCards.js +189 -0
  86. package/vendor/procedural-animals/src/core/build/finEdges.js +85 -0
  87. package/vendor/procedural-animals/src/core/build/furSlope.js +115 -0
  88. package/vendor/procedural-animals/src/core/build/mesh.js +67 -0
  89. package/vendor/procedural-animals/src/core/build/pipeline.js +272 -0
  90. package/vendor/procedural-animals/src/core/build/seams.js +183 -0
  91. package/vendor/procedural-animals/src/core/build/warp.js +112 -0
  92. package/vendor/procedural-animals/src/core/build/weights.js +393 -0
  93. package/vendor/procedural-animals/src/core/math/vec.js +81 -0
  94. package/vendor/procedural-animals/src/core/motion/actions.js +800 -0
  95. package/vendor/procedural-animals/src/core/motion/bird.js +3063 -0
  96. package/vendor/procedural-animals/src/core/motion/birdActions.js +1059 -0
  97. package/vendor/procedural-animals/src/core/motion/common.js +158 -0
  98. package/vendor/procedural-animals/src/core/motion/index.js +22 -0
  99. package/vendor/procedural-animals/src/core/motion/quadruped.js +2875 -0
  100. package/vendor/procedural-animals/src/core/motion/snake.js +1594 -0
  101. package/vendor/procedural-animals/src/core/motion/spider.js +1810 -0
  102. package/vendor/procedural-animals/src/core/motion/swimmer.js +1047 -0
  103. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +613 -0
  104. package/vendor/procedural-animals/src/core/render/animalObject.js +262 -0
  105. package/vendor/procedural-animals/src/core/render/coatMaterial.js +1301 -0
  106. package/vendor/procedural-animals/src/core/render/dqs.js +159 -0
  107. package/vendor/procedural-animals/src/core/render/eyes.js +676 -0
  108. package/vendor/procedural-animals/src/core/render/membranes.js +77 -0
  109. package/vendor/procedural-animals/src/core/render/skeleton.js +41 -0
  110. package/vendor/procedural-animals/src/core/rig/bird.js +327 -0
  111. package/vendor/procedural-animals/src/core/rig/quadruped.js +76 -0
  112. package/vendor/procedural-animals/src/core/rig/rig.js +79 -0
  113. package/vendor/procedural-animals/src/core/rig/snake.js +76 -0
  114. package/vendor/procedural-animals/src/core/rig/spider.js +110 -0
  115. package/vendor/procedural-animals/src/core/rig/swimmer.js +181 -0
  116. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +53 -0
  117. package/vendor/procedural-animals/src/core/sdf/mesher.js +238 -0
  118. package/vendor/procedural-animals/src/core/sdf/sdf.js +263 -0
  119. package/vendor/procedural-animals/src/index.d.ts +98 -0
  120. package/vendor/procedural-animals/src/index.js +29 -0
  121. package/vendor/procedural-animals/src/registry.js +48 -0
  122. package/vendor/procedural-animals/src/species/bear/behaviour.js +463 -0
  123. package/vendor/procedural-animals/src/species/bear/claws.js +147 -0
  124. package/vendor/procedural-animals/src/species/bear/coat.js +726 -0
  125. package/vendor/procedural-animals/src/species/bear/index.js +139 -0
  126. package/vendor/procedural-animals/src/species/bear/motion.js +112 -0
  127. package/vendor/procedural-animals/src/species/bear/regions.js +78 -0
  128. package/vendor/procedural-animals/src/species/bear/rig.js +112 -0
  129. package/vendor/procedural-animals/src/species/bear/sculpt.js +272 -0
  130. package/vendor/procedural-animals/src/species/boar/behaviour.js +335 -0
  131. package/vendor/procedural-animals/src/species/boar/coat.js +372 -0
  132. package/vendor/procedural-animals/src/species/boar/index.js +110 -0
  133. package/vendor/procedural-animals/src/species/boar/motion.js +85 -0
  134. package/vendor/procedural-animals/src/species/boar/regions.js +88 -0
  135. package/vendor/procedural-animals/src/species/boar/rig.js +111 -0
  136. package/vendor/procedural-animals/src/species/boar/sculpt.js +285 -0
  137. package/vendor/procedural-animals/src/species/cat/behaviour.js +559 -0
  138. package/vendor/procedural-animals/src/species/cat/coat.js +841 -0
  139. package/vendor/procedural-animals/src/species/cat/index.js +211 -0
  140. package/vendor/procedural-animals/src/species/cat/motion.js +101 -0
  141. package/vendor/procedural-animals/src/species/cat/regions.js +82 -0
  142. package/vendor/procedural-animals/src/species/cat/rig.js +100 -0
  143. package/vendor/procedural-animals/src/species/cat/sculpt.js +266 -0
  144. package/vendor/procedural-animals/src/species/cat/whiskers.js +110 -0
  145. package/vendor/procedural-animals/src/species/cheetah/coat.js +427 -0
  146. package/vendor/procedural-animals/src/species/cheetah/index.js +51 -0
  147. package/vendor/procedural-animals/src/species/cheetah/joints.js +3 -0
  148. package/vendor/procedural-animals/src/species/cheetah/motion.js +77 -0
  149. package/vendor/procedural-animals/src/species/cheetah/regions.js +95 -0
  150. package/vendor/procedural-animals/src/species/cheetah/rig.js +66 -0
  151. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +158 -0
  152. package/vendor/procedural-animals/src/species/chicken/coat.js +313 -0
  153. package/vendor/procedural-animals/src/species/chicken/coverts.js +320 -0
  154. package/vendor/procedural-animals/src/species/chicken/index.js +110 -0
  155. package/vendor/procedural-animals/src/species/chicken/motion.js +177 -0
  156. package/vendor/procedural-animals/src/species/chicken/regions.js +66 -0
  157. package/vendor/procedural-animals/src/species/chicken/rig.js +144 -0
  158. package/vendor/procedural-animals/src/species/chicken/sculpt.js +389 -0
  159. package/vendor/procedural-animals/src/species/chicken/wingLook.js +66 -0
  160. package/vendor/procedural-animals/src/species/chicken/wingStack.js +124 -0
  161. package/vendor/procedural-animals/src/species/cow/behaviour.js +521 -0
  162. package/vendor/procedural-animals/src/species/cow/coat.js +465 -0
  163. package/vendor/procedural-animals/src/species/cow/index.js +118 -0
  164. package/vendor/procedural-animals/src/species/cow/motion.js +81 -0
  165. package/vendor/procedural-animals/src/species/cow/regions.js +98 -0
  166. package/vendor/procedural-animals/src/species/cow/rig.js +116 -0
  167. package/vendor/procedural-animals/src/species/cow/sculpt.js +339 -0
  168. package/vendor/procedural-animals/src/species/crow/coat.js +145 -0
  169. package/vendor/procedural-animals/src/species/crow/index.js +70 -0
  170. package/vendor/procedural-animals/src/species/crow/joints.js +3 -0
  171. package/vendor/procedural-animals/src/species/crow/motion.js +101 -0
  172. package/vendor/procedural-animals/src/species/crow/regions.js +50 -0
  173. package/vendor/procedural-animals/src/species/crow/rig.js +83 -0
  174. package/vendor/procedural-animals/src/species/crow/sculpt.js +118 -0
  175. package/vendor/procedural-animals/src/species/deer/behaviour.js +513 -0
  176. package/vendor/procedural-animals/src/species/deer/coat.js +391 -0
  177. package/vendor/procedural-animals/src/species/deer/index.js +106 -0
  178. package/vendor/procedural-animals/src/species/deer/motion.js +97 -0
  179. package/vendor/procedural-animals/src/species/deer/regions.js +60 -0
  180. package/vendor/procedural-animals/src/species/deer/rig.js +124 -0
  181. package/vendor/procedural-animals/src/species/deer/sculpt.js +297 -0
  182. package/vendor/procedural-animals/src/species/dog/behaviour.js +521 -0
  183. package/vendor/procedural-animals/src/species/dog/coat.js +495 -0
  184. package/vendor/procedural-animals/src/species/dog/index.js +144 -0
  185. package/vendor/procedural-animals/src/species/dog/motion.js +118 -0
  186. package/vendor/procedural-animals/src/species/dog/regions.js +61 -0
  187. package/vendor/procedural-animals/src/species/dog/rig.js +129 -0
  188. package/vendor/procedural-animals/src/species/dog/sculpt.js +246 -0
  189. package/vendor/procedural-animals/src/species/eagle/coat.js +250 -0
  190. package/vendor/procedural-animals/src/species/eagle/index.js +76 -0
  191. package/vendor/procedural-animals/src/species/eagle/joints.js +3 -0
  192. package/vendor/procedural-animals/src/species/eagle/motion.js +137 -0
  193. package/vendor/procedural-animals/src/species/eagle/regions.js +57 -0
  194. package/vendor/procedural-animals/src/species/eagle/rig.js +107 -0
  195. package/vendor/procedural-animals/src/species/eagle/sculpt.js +137 -0
  196. package/vendor/procedural-animals/src/species/fish/coat.js +271 -0
  197. package/vendor/procedural-animals/src/species/fish/index.js +88 -0
  198. package/vendor/procedural-animals/src/species/fish/motion.js +92 -0
  199. package/vendor/procedural-animals/src/species/fish/regions.js +27 -0
  200. package/vendor/procedural-animals/src/species/fish/rig.js +143 -0
  201. package/vendor/procedural-animals/src/species/fish/sculpt.js +214 -0
  202. package/vendor/procedural-animals/src/species/fish/variants.js +126 -0
  203. package/vendor/procedural-animals/src/species/fox/behaviour.js +314 -0
  204. package/vendor/procedural-animals/src/species/fox/coat.js +444 -0
  205. package/vendor/procedural-animals/src/species/fox/index.js +120 -0
  206. package/vendor/procedural-animals/src/species/fox/motion.js +81 -0
  207. package/vendor/procedural-animals/src/species/fox/regions.js +59 -0
  208. package/vendor/procedural-animals/src/species/fox/rig.js +91 -0
  209. package/vendor/procedural-animals/src/species/fox/sculpt.js +202 -0
  210. package/vendor/procedural-animals/src/species/frog/behaviour.js +590 -0
  211. package/vendor/procedural-animals/src/species/frog/coat.js +305 -0
  212. package/vendor/procedural-animals/src/species/frog/index.js +97 -0
  213. package/vendor/procedural-animals/src/species/frog/motion.js +69 -0
  214. package/vendor/procedural-animals/src/species/frog/regions.js +46 -0
  215. package/vendor/procedural-animals/src/species/frog/rig.js +156 -0
  216. package/vendor/procedural-animals/src/species/frog/sculpt.js +240 -0
  217. package/vendor/procedural-animals/src/species/goat/behaviour.js +509 -0
  218. package/vendor/procedural-animals/src/species/goat/coat.js +590 -0
  219. package/vendor/procedural-animals/src/species/goat/index.js +149 -0
  220. package/vendor/procedural-animals/src/species/goat/motion.js +95 -0
  221. package/vendor/procedural-animals/src/species/goat/regions.js +98 -0
  222. package/vendor/procedural-animals/src/species/goat/rig.js +181 -0
  223. package/vendor/procedural-animals/src/species/goat/sculpt.js +547 -0
  224. package/vendor/procedural-animals/src/species/horse/coat.js +361 -0
  225. package/vendor/procedural-animals/src/species/horse/coatSeam.js +122 -0
  226. package/vendor/procedural-animals/src/species/horse/index.js +80 -0
  227. package/vendor/procedural-animals/src/species/horse/motion.js +245 -0
  228. package/vendor/procedural-animals/src/species/horse/regions.js +60 -0
  229. package/vendor/procedural-animals/src/species/horse/rig.js +117 -0
  230. package/vendor/procedural-animals/src/species/horse/sculpt.js +316 -0
  231. package/vendor/procedural-animals/src/species/horse/seamWeights.js +272 -0
  232. package/vendor/procedural-animals/src/species/lion/behaviour.js +509 -0
  233. package/vendor/procedural-animals/src/species/lion/coat.js +1016 -0
  234. package/vendor/procedural-animals/src/species/lion/index.js +111 -0
  235. package/vendor/procedural-animals/src/species/lion/motion.js +87 -0
  236. package/vendor/procedural-animals/src/species/lion/regions.js +106 -0
  237. package/vendor/procedural-animals/src/species/lion/rig.js +110 -0
  238. package/vendor/procedural-animals/src/species/lion/sculpt.js +384 -0
  239. package/vendor/procedural-animals/src/species/lion/whiskers.js +132 -0
  240. package/vendor/procedural-animals/src/species/pig/behaviour.js +575 -0
  241. package/vendor/procedural-animals/src/species/pig/coat.js +730 -0
  242. package/vendor/procedural-animals/src/species/pig/ears.js +242 -0
  243. package/vendor/procedural-animals/src/species/pig/index.js +161 -0
  244. package/vendor/procedural-animals/src/species/pig/motion.js +105 -0
  245. package/vendor/procedural-animals/src/species/pig/regions.js +100 -0
  246. package/vendor/procedural-animals/src/species/pig/rig.js +152 -0
  247. package/vendor/procedural-animals/src/species/pig/sculpt.js +382 -0
  248. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +605 -0
  249. package/vendor/procedural-animals/src/species/rabbit/coat.js +285 -0
  250. package/vendor/procedural-animals/src/species/rabbit/index.js +85 -0
  251. package/vendor/procedural-animals/src/species/rabbit/motion.js +85 -0
  252. package/vendor/procedural-animals/src/species/rabbit/regions.js +48 -0
  253. package/vendor/procedural-animals/src/species/rabbit/rig.js +99 -0
  254. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +148 -0
  255. package/vendor/procedural-animals/src/species/rat/behaviour.js +539 -0
  256. package/vendor/procedural-animals/src/species/rat/coat.js +341 -0
  257. package/vendor/procedural-animals/src/species/rat/index.js +111 -0
  258. package/vendor/procedural-animals/src/species/rat/motion.js +90 -0
  259. package/vendor/procedural-animals/src/species/rat/regions.js +92 -0
  260. package/vendor/procedural-animals/src/species/rat/rig.js +112 -0
  261. package/vendor/procedural-animals/src/species/rat/sculpt.js +163 -0
  262. package/vendor/procedural-animals/src/species/rat/whiskers.js +119 -0
  263. package/vendor/procedural-animals/src/species/shark/coat.js +383 -0
  264. package/vendor/procedural-animals/src/species/shark/index.js +104 -0
  265. package/vendor/procedural-animals/src/species/shark/motion.js +69 -0
  266. package/vendor/procedural-animals/src/species/shark/regions.js +34 -0
  267. package/vendor/procedural-animals/src/species/shark/rig.js +194 -0
  268. package/vendor/procedural-animals/src/species/shark/sculpt.js +343 -0
  269. package/vendor/procedural-animals/src/species/shark/variants.js +105 -0
  270. package/vendor/procedural-animals/src/species/sheep/behaviour.js +522 -0
  271. package/vendor/procedural-animals/src/species/sheep/coat.js +529 -0
  272. package/vendor/procedural-animals/src/species/sheep/index.js +152 -0
  273. package/vendor/procedural-animals/src/species/sheep/motion.js +86 -0
  274. package/vendor/procedural-animals/src/species/sheep/neck.js +41 -0
  275. package/vendor/procedural-animals/src/species/sheep/regions.js +62 -0
  276. package/vendor/procedural-animals/src/species/sheep/rig.js +163 -0
  277. package/vendor/procedural-animals/src/species/sheep/sculpt.js +542 -0
  278. package/vendor/procedural-animals/src/species/snake/coat.js +315 -0
  279. package/vendor/procedural-animals/src/species/snake/index.js +73 -0
  280. package/vendor/procedural-animals/src/species/snake/motion.js +51 -0
  281. package/vendor/procedural-animals/src/species/snake/regions.js +51 -0
  282. package/vendor/procedural-animals/src/species/snake/rig.js +108 -0
  283. package/vendor/procedural-animals/src/species/snake/sculpt.js +122 -0
  284. package/vendor/procedural-animals/src/species/spider/coat.js +279 -0
  285. package/vendor/procedural-animals/src/species/spider/index.js +78 -0
  286. package/vendor/procedural-animals/src/species/spider/motion.js +72 -0
  287. package/vendor/procedural-animals/src/species/spider/regions.js +87 -0
  288. package/vendor/procedural-animals/src/species/spider/rig.js +118 -0
  289. package/vendor/procedural-animals/src/species/spider/sculpt.js +182 -0
  290. package/vendor/procedural-animals/src/species/wolf/behaviour.js +160 -0
  291. package/vendor/procedural-animals/src/species/wolf/coat.js +749 -0
  292. package/vendor/procedural-animals/src/species/wolf/index.js +107 -0
  293. package/vendor/procedural-animals/src/species/wolf/motion.js +80 -0
  294. package/vendor/procedural-animals/src/species/wolf/regions.js +57 -0
  295. package/vendor/procedural-animals/src/species/wolf/rig.js +87 -0
  296. package/vendor/procedural-animals/src/species/wolf/sculpt.js +339 -0
  297. 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.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
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
+ }
@@ -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
+ }
@@ -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
+ }