@bitefoundry/retrieviewer 0.0.3 → 0.0.5
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 +11 -0
- package/ASSETS-LICENSE.md +2 -1
- package/ATTRIBUTION.md +6 -1
- package/COMFORT-ART.md +95 -0
- package/DESKTOP-PLATFORMS.md +6 -1
- package/INSTALLING.md +4 -0
- package/PLUGIN.md +13 -10
- package/PREREQUISITES.md +95 -0
- package/PUPPY-MEMORY.md +102 -1
- package/README.ko.md +116 -0
- package/README.md +121 -59
- package/RELEASING.md +33 -13
- package/THIRD-PARTY-NOTICES.md +5 -3
- package/braille.mjs +35 -9
- package/examples/live.mjs +2 -2
- package/integrations/linux-overlay/overlay.py +8 -2
- package/integrations/macos-overlay/overlay.jxa +9 -7
- package/integrations/opencode/runtime.mjs +4 -4
- package/integrations/opencode/tui.tsx +1 -1
- package/integrations/windows-overlay/Overlay.cs +7 -6
- package/integrations/windows-overlay/desktop.mjs +2 -1
- package/integrations/windows-overlay/protocol.mjs +13 -7
- package/integrations/windows-overlay/worker.mjs +1 -1
- package/package.json +34 -13
- package/puppy-comfort-sprites.mjs +33 -0
- package/puppy-companion-comfort-q5.bin.gz +0 -0
- package/puppy-companion-comfort.json +140 -0
- package/puppy-companion-life.mjs +58 -18
- package/puppy-companion-objects.mjs +12 -0
- package/puppy-companion-sprites.mjs +4 -2
- package/puppy-frame-predictive.mjs +15 -9
- package/puppy-frame-store.mjs +2 -2
- package/puppy-paper-actions.mjs +4 -2
- package/puppy-paper-behaviors.mjs +1 -1
- package/puppy-paper-contact.mjs +4 -2
- package/puppy-paper-seat.mjs +4 -2
- package/puppy-paper-world.mjs +14 -0
- package/puppy-paper.mjs +79 -21
- package/retrieviewer-cli.mjs +8 -6
- package/retrieviewer-plugin.d.mts +1 -1
- package/retrieviewer-plugin.mjs +1 -1
- package/retrieviewer.d.mts +12 -4
- package/retrieviewer.mjs +20 -14
- package/locomotion-core.mjs +0 -21
- package/locomotion-puppy.animal +0 -0
- package/vendor/procedural-animals/package.json +0 -40
- package/vendor/procedural-animals/src/animal.js +0 -146
- package/vendor/procedural-animals/src/bake.js +0 -51
- package/vendor/procedural-animals/src/build.js +0 -81
- package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
- package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
- package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
- package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
- package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
- package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
- package/vendor/procedural-animals/src/core/build/seams.js +0 -183
- package/vendor/procedural-animals/src/core/build/warp.js +0 -112
- package/vendor/procedural-animals/src/core/build/weights.js +0 -393
- package/vendor/procedural-animals/src/core/math/vec.js +0 -81
- package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
- package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
- package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
- package/vendor/procedural-animals/src/core/motion/common.js +0 -158
- package/vendor/procedural-animals/src/core/motion/index.js +0 -22
- package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
- package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
- package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
- package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
- package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
- package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
- package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
- package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
- package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
- package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
- package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
- package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
- package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
- package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
- package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
- package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
- package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
- package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
- package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
- package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
- package/vendor/procedural-animals/src/index.d.ts +0 -98
- package/vendor/procedural-animals/src/index.js +0 -29
- package/vendor/procedural-animals/src/registry.js +0 -48
- package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
- package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
- package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
- package/vendor/procedural-animals/src/species/bear/index.js +0 -139
- package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
- package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
- package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
- package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
- package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
- package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
- package/vendor/procedural-animals/src/species/boar/index.js +0 -110
- package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
- package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
- package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
- package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
- package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
- package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
- package/vendor/procedural-animals/src/species/cat/index.js +0 -211
- package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
- package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
- package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
- package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
- package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
- package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
- package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
- package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
- package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
- package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
- package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
- package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
- package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
- package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
- package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
- package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
- package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
- package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
- package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
- package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
- package/vendor/procedural-animals/src/species/cow/index.js +0 -118
- package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
- package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
- package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
- package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
- package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
- package/vendor/procedural-animals/src/species/crow/index.js +0 -70
- package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
- package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
- package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
- package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
- package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
- package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
- package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
- package/vendor/procedural-animals/src/species/deer/index.js +0 -106
- package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
- package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
- package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
- package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
- package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
- package/vendor/procedural-animals/src/species/dog/index.js +0 -144
- package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
- package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
- package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
- package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
- package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
- package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
- package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
- package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
- package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
- package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
- package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
- package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
- package/vendor/procedural-animals/src/species/fish/index.js +0 -88
- package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
- package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
- package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
- package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
- package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
- package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
- package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
- package/vendor/procedural-animals/src/species/fox/index.js +0 -120
- package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
- package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
- package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
- package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
- package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
- package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
- package/vendor/procedural-animals/src/species/frog/index.js +0 -97
- package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
- package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
- package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
- package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
- package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
- package/vendor/procedural-animals/src/species/goat/index.js +0 -149
- package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
- package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
- package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
- package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
- package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
- package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
- package/vendor/procedural-animals/src/species/horse/index.js +0 -80
- package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
- package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
- package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
- package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
- package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
- package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
- package/vendor/procedural-animals/src/species/lion/index.js +0 -111
- package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
- package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
- package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
- package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
- package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
- package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
- package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
- package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
- package/vendor/procedural-animals/src/species/pig/index.js +0 -161
- package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
- package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
- package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
- package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
- package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
- package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
- package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
- package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
- package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
- package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
- package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
- package/vendor/procedural-animals/src/species/rat/index.js +0 -111
- package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
- package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
- package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
- package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
- package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
- package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
- package/vendor/procedural-animals/src/species/shark/index.js +0 -104
- package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
- package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
- package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
- package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
- package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
- package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
- package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
- package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
- package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
- package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
- package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
- package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
- package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
- package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
- package/vendor/procedural-animals/src/species/snake/index.js +0 -73
- package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
- package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
- package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
- package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
- package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
- package/vendor/procedural-animals/src/species/spider/index.js +0 -78
- package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
- package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
- package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
- package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
- package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
- package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
- package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
- package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
- package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
- package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
- package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
- package/vendor/procedural-animals/src/worker.js +0 -29
|
@@ -61,6 +61,6 @@ try{
|
|
|
61
61
|
const {createPet}=await import('../../retrieviewer.mjs');const pet=await createPet();
|
|
62
62
|
if(stopping)pet.dispose();else{
|
|
63
63
|
pump=createFramePump({pet,send:write});if(pendingViewport)pump.viewport(pendingViewport);
|
|
64
|
-
write({type:'loaded'});timer=setInterval(()=>{try{pump.tick();}catch(error){write({type:'error',message:error.message});stop();}},1000/spec.fps);
|
|
64
|
+
write({type:'loaded',ink:process.env.RETRIEVIEWER_INK??'cream'});timer=setInterval(()=>{try{pump.tick();}catch(error){write({type:'error',message:error.message});stop();}},1000/spec.fps);
|
|
65
65
|
}
|
|
66
66
|
}catch(error){sendParent({error:error.message});await stop();}
|
package/package.json
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitefoundry/retrieviewer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "A fluffy Braille desktop pet for Windows and Linux X11, with experimental macOS support and an embeddable TUI engine.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
-
"homepage": "https://github.
|
|
7
|
-
"
|
|
6
|
+
"homepage": "https://bitefoundry.github.io/retrieviewer/",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/BiteFoundry/retrieviewer.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/BiteFoundry/retrieviewer/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"tui",
|
|
16
|
+
"braille",
|
|
17
|
+
"pet",
|
|
18
|
+
"retriever",
|
|
19
|
+
"opencode",
|
|
20
|
+
"desktop-pet",
|
|
21
|
+
"windows",
|
|
22
|
+
"linux",
|
|
23
|
+
"macos",
|
|
24
|
+
"overlay"
|
|
25
|
+
],
|
|
8
26
|
"publishConfig": {
|
|
9
27
|
"access": "public",
|
|
10
28
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -64,16 +82,17 @@
|
|
|
64
82
|
"DESKTOP-PLATFORMS.md",
|
|
65
83
|
"WINDOWS-COMPANION.md",
|
|
66
84
|
"INSTALLING.md",
|
|
85
|
+
"PREREQUISITES.md",
|
|
86
|
+
"README.ko.md",
|
|
67
87
|
"PLUGIN.md",
|
|
68
88
|
"EMBEDDING.md",
|
|
69
89
|
"PUPPY-MEMORY.md",
|
|
70
90
|
"PUPPY-Q5-COMPARISON.md",
|
|
91
|
+
"COMFORT-ART.md",
|
|
71
92
|
"examples/embed.mjs",
|
|
72
93
|
"examples/live.mjs",
|
|
73
94
|
"examples/plugin.mjs",
|
|
74
95
|
"examples/bridge.py",
|
|
75
|
-
"locomotion-core.mjs",
|
|
76
|
-
"locomotion-puppy.animal",
|
|
77
96
|
"braille.mjs",
|
|
78
97
|
"puppy-frame-store.mjs",
|
|
79
98
|
"puppy-frame-predictive.mjs",
|
|
@@ -91,6 +110,7 @@
|
|
|
91
110
|
"puppy-companion-life.mjs",
|
|
92
111
|
"puppy-companion-objects.mjs",
|
|
93
112
|
"puppy-companion-sprites.mjs",
|
|
113
|
+
"puppy-comfort-sprites.mjs",
|
|
94
114
|
"puppy-mouth-anchor.mjs",
|
|
95
115
|
"puppy-mouth-anchor.json",
|
|
96
116
|
"puppy-clean.mjs",
|
|
@@ -116,24 +136,25 @@
|
|
|
116
136
|
"puppy-paper-actions-v9.json",
|
|
117
137
|
"puppy-companion-interactions-v3-q5.bin.gz",
|
|
118
138
|
"puppy-companion-interactions-v3.json",
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"vendor/procedural-animals/
|
|
139
|
+
"puppy-companion-comfort-q5.bin.gz",
|
|
140
|
+
"puppy-companion-comfort.json",
|
|
141
|
+
"vendor/procedural-animals/LICENSE"
|
|
122
142
|
],
|
|
123
143
|
"scripts": {
|
|
124
|
-
"start": "node
|
|
125
|
-
"
|
|
126
|
-
"pet": "node puppy-terminal.mjs",
|
|
144
|
+
"start": "node tools/preview-site.mjs",
|
|
145
|
+
"build:site": "node tools/build-site.mjs",
|
|
127
146
|
"pet:companion": "node examples/live.mjs",
|
|
128
147
|
"pet:desktop": "node retrieviewer-cli.mjs desktop",
|
|
129
148
|
"test": "node --test \"*.test.mjs\"",
|
|
130
|
-
"test:locomotion": "node check-locomotion.mjs",
|
|
131
149
|
"test:package": "node check-pet-package.mjs",
|
|
132
150
|
"release:check": "node tools/check-release.mjs",
|
|
133
151
|
"prepublishOnly": "npm run release:check"
|
|
134
152
|
},
|
|
135
153
|
"dependencies": {
|
|
136
|
-
"jsonc-parser": "3.3.1"
|
|
154
|
+
"jsonc-parser": "3.3.1"
|
|
155
|
+
},
|
|
156
|
+
"devDependencies": {
|
|
157
|
+
"playwright": "1.64.1",
|
|
137
158
|
"three": "0.186.1"
|
|
138
159
|
}
|
|
139
160
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {grayFrameReader,isGrayFrameSource} from './puppy-frame-store.mjs';
|
|
2
|
+
|
|
3
|
+
// A handful of authored keys, not an expanded 30fps film or a live image morph.
|
|
4
|
+
// First/last keys are the exact shared seated source; all keys use one scale.
|
|
5
|
+
export function comfortFrameIndex(progress,info){
|
|
6
|
+
if(!Number.isFinite(progress)||progress<0||progress>1)throw Error('Invalid comfort progress');
|
|
7
|
+
const seconds=progress*6;
|
|
8
|
+
if(seconds<.12||progress===1)return 0;
|
|
9
|
+
if(seconds<.65)return seconds<.3?1:2;
|
|
10
|
+
if(seconds>5.15)return seconds<5.45?7:seconds<5.8?8:0;
|
|
11
|
+
const loop=[3,4,3,5,3,6,3,5,3,4,3,6];
|
|
12
|
+
return loop[Math.floor((seconds-.65)/.28)%loop.length];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createComfortSpriteSampler(bytes,info,output){
|
|
16
|
+
if(!isGrayFrameSource(bytes)||![1,2].includes(info?.version)||info.width!==320||info.height!==320||info.frames!==(info.version===2?13:9))throw Error('Invalid comfort sprites');
|
|
17
|
+
if(output!==undefined&&(!(output instanceof Uint8ClampedArray)||output.length!==320*320*4))throw Error('Invalid comfort output');
|
|
18
|
+
const frames=grayFrameReader(bytes,320,320,info.frames);let rgba=output??null;
|
|
19
|
+
if(rgba)for(let i=3;i<rgba.length;i+=4)rgba[i]=255;
|
|
20
|
+
return pose=>{
|
|
21
|
+
if(!['tug','sleep'].includes(pose?.clip))throw Error('Invalid comfort clip');
|
|
22
|
+
if(!rgba){rgba=new Uint8ClampedArray(320*320*4);for(let i=3;i<rgba.length;i+=4)rgba[i]=255;}
|
|
23
|
+
const index=pose.clip==='sleep'?info.sleep?.[pose.variant]:comfortFrameIndex(pose.progress,info);
|
|
24
|
+
if(!Number.isInteger(index))throw Error('Invalid sleep variant');
|
|
25
|
+
const frame=frames.getFrame(index),base=pose.base,blend=pose.blend??1;
|
|
26
|
+
if(!Number.isFinite(blend)||blend<0||blend>1)throw Error('Invalid sleep blend');
|
|
27
|
+
for(let i=0,j=0;i<frame.length;i++,j+=4){
|
|
28
|
+
const v=frame[pose.right?Math.floor(i/320)*320+319-i%320:i];
|
|
29
|
+
rgba[j]=rgba[j+1]=rgba[j+2]=base&&blend<1?Math.round(base[j]+(v-base[j])*blend):v;
|
|
30
|
+
}
|
|
31
|
+
return rgba;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 2,
|
|
3
|
+
"width": 320,
|
|
4
|
+
"height": 320,
|
|
5
|
+
"frames": 13,
|
|
6
|
+
"clips": [
|
|
7
|
+
"tug",
|
|
8
|
+
"sleep"
|
|
9
|
+
],
|
|
10
|
+
"gzipBytes": 129148,
|
|
11
|
+
"residentPixelBytes": 341139,
|
|
12
|
+
"sourceSheetSha256": "10fde9dacca5cb45acd68f387e7ed3bcf88cd72cf0f9c4220d31d819db91731e",
|
|
13
|
+
"neutralSha256": "19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a",
|
|
14
|
+
"encodedSha256": "35327cc103b1f7ac2ff1b09ed98658fd8ff1dcef322de9c9b18071a4358b7b87",
|
|
15
|
+
"method": "Built-in imagegen authored tug keys. One fixed scale, ground/center translation only. Exact existing Q5 seat first/last. No expanded tween film or live body deformation.",
|
|
16
|
+
"registration": {
|
|
17
|
+
"sheetSize": [
|
|
18
|
+
1774,
|
|
19
|
+
887
|
|
20
|
+
],
|
|
21
|
+
"targetBounds": [
|
|
22
|
+
41,
|
|
23
|
+
92,
|
|
24
|
+
231,
|
|
25
|
+
301
|
|
26
|
+
],
|
|
27
|
+
"registration": [
|
|
28
|
+
{
|
|
29
|
+
"cell": 0,
|
|
30
|
+
"scale": 0.5663956639566395,
|
|
31
|
+
"dx": 32,
|
|
32
|
+
"dy": 69
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"cell": 1,
|
|
36
|
+
"scale": 0.5663956639566395,
|
|
37
|
+
"dx": 39,
|
|
38
|
+
"dy": 69
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"cell": 2,
|
|
42
|
+
"scale": 0.5663956639566395,
|
|
43
|
+
"dx": 39,
|
|
44
|
+
"dy": 69
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"cell": 3,
|
|
48
|
+
"scale": 0.5663956639566395,
|
|
49
|
+
"dx": 35,
|
|
50
|
+
"dy": 68
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"cell": 4,
|
|
54
|
+
"scale": 0.5663956639566395,
|
|
55
|
+
"dx": 33,
|
|
56
|
+
"dy": 74
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"cell": 5,
|
|
60
|
+
"scale": 0.5663956639566395,
|
|
61
|
+
"dx": 39,
|
|
62
|
+
"dy": 74
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"cell": 6,
|
|
66
|
+
"scale": 0.5663956639566395,
|
|
67
|
+
"dx": 39,
|
|
68
|
+
"dy": 74
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"cell": 7,
|
|
72
|
+
"scale": 0.5663956639566395,
|
|
73
|
+
"dx": 36,
|
|
74
|
+
"dy": 74
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
"sleep": {
|
|
79
|
+
"side": 9,
|
|
80
|
+
"belly": 10,
|
|
81
|
+
"curl": 11,
|
|
82
|
+
"chin": 12
|
|
83
|
+
},
|
|
84
|
+
"sleepRegistration": [
|
|
85
|
+
{
|
|
86
|
+
"key": "side",
|
|
87
|
+
"sourceBounds": [
|
|
88
|
+
26,
|
|
89
|
+
461,
|
|
90
|
+
1234,
|
|
91
|
+
873
|
|
92
|
+
],
|
|
93
|
+
"width": 254,
|
|
94
|
+
"scale": 0.21026490066225165,
|
|
95
|
+
"ground": 300
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"key": "belly",
|
|
99
|
+
"sourceBounds": [
|
|
100
|
+
28,
|
|
101
|
+
413,
|
|
102
|
+
1239,
|
|
103
|
+
881
|
|
104
|
+
],
|
|
105
|
+
"width": 224,
|
|
106
|
+
"scale": 0.18497109826589594,
|
|
107
|
+
"ground": 300
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"key": "curl",
|
|
111
|
+
"sourceBounds": [
|
|
112
|
+
44,
|
|
113
|
+
373,
|
|
114
|
+
1213,
|
|
115
|
+
992
|
|
116
|
+
],
|
|
117
|
+
"width": 216,
|
|
118
|
+
"scale": 0.1847733105218135,
|
|
119
|
+
"ground": 300
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"key": "chin",
|
|
123
|
+
"sourceBounds": [
|
|
124
|
+
116,
|
|
125
|
+
435,
|
|
126
|
+
1218,
|
|
127
|
+
953
|
|
128
|
+
],
|
|
129
|
+
"width": 198,
|
|
130
|
+
"scale": 0.17967332123411978,
|
|
131
|
+
"ground": 300
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"sleepSourceHashes": {
|
|
135
|
+
"side": "85c567eb0958a213ee5b93d0a8592639489f5f29dded35e0d1d22e920ed1fe9f",
|
|
136
|
+
"belly": "e1967d9156a119d04e25fd6428fe5dcdbd2156c5e4eba0347217847874006109",
|
|
137
|
+
"curl": "10c9a85701af3587c48c1d8158972a07026e79a18a2375d86108538eda05aae7",
|
|
138
|
+
"chin": "e971eaa6861b597f0dba3a487403cee5f120cba0a9f9584d831b5634d096dee7"
|
|
139
|
+
}
|
|
140
|
+
}
|
package/puppy-companion-life.mjs
CHANGED
|
@@ -11,16 +11,18 @@ const BALL_TARGET={x:0,z:-4};
|
|
|
11
11
|
const OFFER={x:0,z:.3};
|
|
12
12
|
// Hand-fed treat marker, relative to the puppy's current root (no travel for treats).
|
|
13
13
|
const TREAT_OFFSET={z:.08,height:.25};
|
|
14
|
-
const COOLDOWN={ball:6,treat:15};
|
|
14
|
+
const COOLDOWN={ball:6,treat:15,tug:20};
|
|
15
15
|
const FLIGHT=.65,BALL_PEAK=.75,CARRY_HEIGHT=.19,SETTLE_FALLBACK=.6,MAX_DT=.25,ARRIVE=.05;
|
|
16
16
|
const LABEL={
|
|
17
17
|
start:'기다리는 중',pause:'잠시 느긋하게 둘러보는 중',lie:'엎드리는 중',rest:'엎드려 쉬는 중',recover:'앉아서 기운 차리는 중',
|
|
18
18
|
sit:'앉는 중',watch:'앉아서 지켜보는 중',look:'고개를 돌려 살피는 중',observe:'가만히 주변 관찰 중',
|
|
19
19
|
stroll:'옆으로 살짝 걸어가는 중',sniff:'잠깐 멈춰 주변을 살피는 중',dash:'저 멀리 달려가는 중',far:'멀리서 둘러보는 중',home:'제자리로 돌아오는 중',
|
|
20
|
+
patrol:'주변을 왕복 산책하는 중',scan:'양쪽을 번갈아 살피는 중',roll:'느긋하게 뒹구는 중',play:'신나서 한 바퀴 도는 중',checkin:'가까이 와서 함께 쉬는 중',
|
|
21
|
+
belly:'배를 보이고 발라당 쉬는 중',sleep:'새근새근 잠자는 중',tug:'장난감을 물고 당기는 중',
|
|
20
22
|
fetch:'공을 쫓아가는 중',pickup:'공을 무는 중',carry:'공을 물고 돌아오는 중',drop:'공을 내려놓는 중',offer:'공을 내려놓고 기다리는 중',
|
|
21
23
|
treatSit:'간식 앞에 앉는 중',chew:'간식 먹는 중'
|
|
22
24
|
};
|
|
23
|
-
const PENDING_LABEL={treat:'곧 간식'};
|
|
25
|
+
const PENDING_LABEL={treat:'곧 간식',tug:'곧 터그놀이'};
|
|
24
26
|
// Baked interaction clips, played only while holding at the shared seated endpoint.
|
|
25
27
|
const GESTURE={'ball-pickup':1.4,'ball-drop':1.2,'treat-eat':2.4};
|
|
26
28
|
const clamp=(v,a,b)=>Math.min(b,Math.max(a,v));
|
|
@@ -37,9 +39,10 @@ export function createCompanionLife(actor,{seed=731,energy=.8}={}){
|
|
|
37
39
|
if(!Number.isFinite(energy)||energy<0||energy>1)throw RangeError('energy must be within 0..1');
|
|
38
40
|
|
|
39
41
|
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
|
-
|
|
42
|
+
const needs={energy,social:.5,curiosity:.5,drowsiness:0};
|
|
43
|
+
const cooldowns={ball:0,treat:0,tug:0};
|
|
44
|
+
const episodeCooldowns={roll:0,play:0,belly:0,sleep:0};
|
|
45
|
+
let clock=0,decisions=0,lastEpisode=null,quiet=0;
|
|
43
46
|
let queue=[],hold=0,holdIntent=null,waiting=null,gesture=null;
|
|
44
47
|
let intent='start',label=LABEL.start,pending=null,active=null,ball=null,treat=null;
|
|
45
48
|
|
|
@@ -51,25 +54,47 @@ export function createCompanionLife(actor,{seed=731,energy=.8}={}){
|
|
|
51
54
|
// Treats accept any seat variant at the front-seated endpoint: the hand comes to the puppy.
|
|
52
55
|
const seatedAnyVariant=()=>{const s=actor.sample(clock);return actor.state==='idle'&&s.seatProgress===1&&s.view==='approach';};
|
|
53
56
|
const fx=fn=>({fx:fn});
|
|
54
|
-
const home=()=>cmd('go',[HOME.x,HOME.z],'home');
|
|
57
|
+
const home=()=>cmd('go',[HOME.x,HOME.z],'home',()=>{const s=actor.sample(clock);return Math.hypot(s.x-HOME.x,s.z-HOME.z)>ARRIVE;});
|
|
58
|
+
const sit=step=>cmd('sit',[],step,()=>!seatedAnyVariant());
|
|
59
|
+
const lie=()=>cmd('lie',[],'lie',()=>actor.state!=='down');
|
|
60
|
+
const walkTo=x=>cmd('walk',()=>{const dx=x-actor.sample(clock).x;return [dx<0?'left':'right',Math.abs(dx)];},'patrol',()=>Math.abs(x-actor.sample(clock).x)>.002);
|
|
55
61
|
|
|
56
62
|
// Each episode is a short coherent plan; a pause always leads in so autonomy never stalls.
|
|
57
63
|
const EPISODES={
|
|
58
|
-
rest:()=>[
|
|
59
|
-
watch:()=>[
|
|
60
|
-
observe:()=>[cmd('look',[side()],'look'),wait(range(3,9),'observe'),fx(()=>{needs.curiosity-=.15;})],
|
|
64
|
+
rest:()=>[lie(),wait(range(10,18),'rest'),sit('recover'),wait(range(3,6),'recover')],
|
|
65
|
+
watch:()=>[sit('sit'),cmd('look',[side()],'look'),wait(range(3,9),'watch'),fx(()=>{needs.social-=.3;needs.curiosity+=.1;})],
|
|
66
|
+
observe:()=>[sit('sit'),cmd('look',[side()],'look'),wait(range(3,9),'observe'),fx(()=>{needs.curiosity-=.15;})],
|
|
61
67
|
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;})]
|
|
68
|
+
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;})],
|
|
69
|
+
scan:()=>[sit('sit'),cmd('look',['left'],'scan'),wait(range(.5,1.5),'scan'),cmd('look',['right'],'scan'),wait(range(2,4),'observe'),fx(()=>{needs.curiosity-=.25;})],
|
|
70
|
+
patrol:()=>{const x=actor.sample(clock).x,d=range(.16,.3)*(rand()<.5?-1:1);return [walkTo(x+d),wait(range(.6,1.2),'sniff'),walkTo(x-d),wait(range(.6,1.2),'sniff'),walkTo(x),wait(range(1,3),'observe'),fx(()=>{needs.energy-=.1;needs.curiosity-=.25;})];},
|
|
71
|
+
roll:()=>[lie(),wait(range(.7,1.5),'rest'),cmd('roll',[],'roll'),wait(range(2,5),'watch'),fx(()=>{needs.energy-=.08;needs.curiosity-=.15;})],
|
|
72
|
+
checkin:()=>[home(),sit('sit'),cmd('look',[side()],'look'),wait(range(5,10),'checkin'),fx(()=>{needs.social-=.4;})],
|
|
73
|
+
play:()=>[cmd('spin',[],'play'),wait(range(1,2),'pause'),sit('sit'),wait(range(2,4),'watch'),fx(()=>{needs.energy-=.12;needs.curiosity-=.2;})],
|
|
74
|
+
belly:()=>[cmd('belly',[range(5,9)],'belly'),wait(range(2,4),'watch'),fx(()=>{needs.energy+=.08;needs.curiosity-=.15;})],
|
|
75
|
+
sleep:()=>[cmd('sleep',[range(65,110),['side','curl','chin','belly'][Math.floor(rand()*4)],rand()<.5],'sleep'),wait(range(2,4),'recover'),fx(()=>{needs.energy+=.3;})],
|
|
63
76
|
};
|
|
64
77
|
const weights=()=>{
|
|
65
78
|
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
|
|
79
|
+
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,
|
|
80
|
+
scan:.35+c*.4,patrol:e>.25?.7*c*e:0,checkin:.25+s*.7,
|
|
81
|
+
roll:episodeCooldowns.roll===0&&e>.45?.35*e:0,
|
|
82
|
+
play:episodeCooldowns.play===0&&e>.6&&typeof actor.spin==='function'?.25*e*c:0,
|
|
83
|
+
belly:episodeCooldowns.belly===0&&typeof actor.belly==='function'?.35:0,
|
|
84
|
+
sleep:episodeCooldowns.sleep===0&&typeof actor.sleep==='function'?(e<.4?3:.2):0};
|
|
67
85
|
};
|
|
68
86
|
function decide(){
|
|
69
87
|
const w=weights();if(lastEpisode)w[lastEpisode]=0;
|
|
70
88
|
const kinds=Object.keys(w),total=kinds.reduce((sum,k)=>sum+w[k],0);
|
|
71
89
|
let pick=rand()*total,kind=kinds.find(k=>(pick-=w[k])<0)??'observe';
|
|
90
|
+
// Quiet-time sleep pressure is independent of energy restored by sitting.
|
|
91
|
+
// Wait for the current coherent episode to end; never yank a running puppy.
|
|
92
|
+
if(quiet>=120&&needs.drowsiness>=.35&&episodeCooldowns.sleep===0&&lastEpisode!=='sleep'&&typeof actor.sleep==='function')kind='sleep';
|
|
72
93
|
lastEpisode=kind;decisions++;
|
|
94
|
+
if(kind==='roll')episodeCooldowns.roll=90;
|
|
95
|
+
if(kind==='play')episodeCooldowns.play=120;
|
|
96
|
+
if(kind==='belly')episodeCooldowns.belly=80;
|
|
97
|
+
if(kind==='sleep')episodeCooldowns.sleep=100;
|
|
73
98
|
queue=[wait(range(3,9),'pause'),...EPISODES[kind]()];
|
|
74
99
|
}
|
|
75
100
|
|
|
@@ -88,16 +113,22 @@ export function createCompanionLife(actor,{seed=731,energy=.8}={}){
|
|
|
88
113
|
fx(()=>{treat=true;}),cmd('sit',[],'treatSit',()=>!seatedAnyVariant()),
|
|
89
114
|
play('treat-eat','chew'),fx(()=>{treat=null;needs.energy+=.25;needs.social-=.3;})
|
|
90
115
|
];
|
|
116
|
+
const TUG_STEPS=()=>[
|
|
117
|
+
cmd('sit',[],'tug',unseated),cmd('tug',[6],'tug'),wait(.5,'watch'),fx(()=>{needs.energy-=.12;needs.social-=.4;})
|
|
118
|
+
];
|
|
91
119
|
|
|
92
120
|
function startInteraction(){
|
|
93
121
|
active=pending;pending=null;decisions++;hold=0;
|
|
94
|
-
queue=active==='ball'?BALL_STEPS():TREAT_STEPS();
|
|
122
|
+
queue=active==='ball'?BALL_STEPS():active==='tug'?TUG_STEPS():TREAT_STEPS();
|
|
95
123
|
}
|
|
96
124
|
function finishInteraction(){cooldowns[active]=COOLDOWN[active];active=null;}
|
|
97
125
|
|
|
98
126
|
function drift(dt){
|
|
99
|
-
const resting=holdIntent==='rest'||holdIntent==='recover';
|
|
127
|
+
const resting=holdIntent==='rest'||holdIntent==='recover'||actor.state==='sleep'||intent==='belly';
|
|
100
128
|
needs.energy+=resting?.04*dt:-.004*dt;
|
|
129
|
+
const asleep=actor.state==='sleep';
|
|
130
|
+
needs.drowsiness+=asleep?-dt/60:dt/240;
|
|
131
|
+
quiet=active||pending||asleep?0:quiet+dt;
|
|
101
132
|
if(!active){needs.curiosity+=.01*dt;needs.social+=.008*dt;}
|
|
102
133
|
for(const k in needs)needs[k]=clamp(needs[k],0,1);
|
|
103
134
|
}
|
|
@@ -106,6 +137,7 @@ export function createCompanionLife(actor,{seed=731,energy=.8}={}){
|
|
|
106
137
|
if(typeof dt!=='number'||!Number.isFinite(dt)||dt<0)throw RangeError('dt must be a finite non-negative number');
|
|
107
138
|
dt=Math.min(dt,MAX_DT);clock+=dt;
|
|
108
139
|
for(const k in cooldowns)cooldowns[k]=Math.max(0,cooldowns[k]-dt);
|
|
140
|
+
for(const k in episodeCooldowns)episodeCooldowns[k]=Math.max(0,episodeCooldowns[k]-dt);
|
|
109
141
|
drift(dt);
|
|
110
142
|
const safe=SAFE.has(actor.state);
|
|
111
143
|
if(waiting){
|
|
@@ -133,15 +165,22 @@ export function createCompanionLife(actor,{seed=731,energy=.8}={}){
|
|
|
133
165
|
if(step.when&&!step.when())continue;
|
|
134
166
|
intent=step.intent;label=step.label;
|
|
135
167
|
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};
|
|
168
|
+
if(actor[step.cmd](...(typeof step.args==='function'?step.args():step.args))!==false)waiting={age:0,left:false};
|
|
137
169
|
return;
|
|
138
170
|
}
|
|
139
171
|
}
|
|
140
172
|
|
|
141
173
|
function interact(kind){
|
|
142
|
-
if(
|
|
174
|
+
if(!['ball','treat','tug'].includes(kind))return false;
|
|
175
|
+
if(kind==='tug'&&typeof actor.tug!=='function')return false;
|
|
143
176
|
if(pending||active||cooldowns[kind]>0)return false;
|
|
144
|
-
|
|
177
|
+
quiet=0;
|
|
178
|
+
if(kind==='treat'||kind==='tug'){
|
|
179
|
+
pending=kind;
|
|
180
|
+
// The pet wakes through its authored recovery, not after a long sleep timer.
|
|
181
|
+
if(['sleep','belly'].includes(actor.sample(clock).state))actor.sit();
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
145
184
|
// Ball: launch now and drop obsolete controller plans; the actor's own state is left to chase.
|
|
146
185
|
active='ball';decisions++;ball={mode:'flight',start:clock};
|
|
147
186
|
queue=BALL_STEPS();hold=0;holdIntent=null;gesture=null;waiting=null;
|
|
@@ -172,8 +211,9 @@ export function createCompanionLife(actor,{seed=731,energy=.8}={}){
|
|
|
172
211
|
get report(){
|
|
173
212
|
const interaction=active??pending;
|
|
174
213
|
return {
|
|
175
|
-
intent,label:pending?`${label} · ${PENDING_LABEL[pending]}`:label,interaction,busy:interaction!==null,
|
|
176
|
-
ball:ballReport(),treat:treatReport(),
|
|
214
|
+
intent,label:pending?`${label} · ${PENDING_LABEL[pending]}`:label,episode:lastEpisode,interaction,busy:interaction!==null,
|
|
215
|
+
ball:ballReport(),treat:treatReport(),tug:actor.state==='tug'?{progress:actor.sample(clock).comfortPose?.progress??0,grip:1}:null,
|
|
216
|
+
snore:actor.state==='sleep'?((clock%3.6)/3.6):null,energy:needs.energy,drowsiness:needs.drowsiness,decisions,cooldowns:{...cooldowns},
|
|
177
217
|
// Local hold clock only: progress freezes between updates; null outside the stationary hold.
|
|
178
218
|
gesture:gesture&&SAFE.has(actor.state)?{clip:gesture.clip,progress:clamp(gesture.elapsed/gesture.duration,0,1)}:null
|
|
179
219
|
};
|
|
@@ -7,6 +7,18 @@ export function paintCompanionObjects(pixels,width,height,projection,report,stat
|
|
|
7
7
|
// Interaction drawings already include the toy/food. Never paint a second
|
|
8
8
|
// floating ball over the baked mouth, or a biscuit through the puppy's chest.
|
|
9
9
|
if(report.gesture)return pixels;
|
|
10
|
+
// A quiet, tiny rising "z" suggests snoring. The sleeping dog itself remains
|
|
11
|
+
// the original eyes-closed source pose: no chest/body zoom or squashing.
|
|
12
|
+
if(Number.isFinite(report.snore)&&state.state==='sleep'){
|
|
13
|
+
const placement=projection.placement(state.x,state.z),side=height*placement.size,sideX=side/placement.pixelAspect;
|
|
14
|
+
const left=width*placement.x-sideX/2,top=height*placement.y-300/320*side;
|
|
15
|
+
const cycle=report.snore,tone=Math.round(140*Math.sin(Math.PI*cycle)),unit=Math.max(1,Math.round(side/160));
|
|
16
|
+
const cx=Math.round(left+220/320*sideX),cy=Math.round(top+(210-16*cycle)/320*side);
|
|
17
|
+
if(tone>12)for(const [gx,gy] of [[0,0],[1,0],[2,0],[1,1],[0,2],[1,2],[2,2]])for(let dy=0;dy<unit;dy++)for(let dx=0;dx<unit;dx++){
|
|
18
|
+
const x=cx+gx*unit+dx,y=cy+gy*unit+dy;if(x<0||x>=width||y<0||y>=height)continue;
|
|
19
|
+
const j=(y*width+x)*4;pixels[j]=pixels[j+1]=pixels[j+2]=Math.max(pixels[j],tone);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
10
22
|
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
23
|
else if(report.ball)objects.push({...report.ball,radius:.035,kind:'ball'});
|
|
12
24
|
if(report.treat)objects.push({...report.treat,height:report.treat.height??.018,radius:.022,kind:'treat'});
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {grayFrameReader,isGrayFrameSource} from './puppy-frame-store.mjs';
|
|
2
2
|
// Prebaked interaction samples; the original seat is the exact shared endpoint.
|
|
3
3
|
// Pure sampling, no live image morph, root motion, camera or pose-size fitting.
|
|
4
|
-
export function createCompanionSpriteSampler(bytes,info){
|
|
4
|
+
export function createCompanionSpriteSampler(bytes,info,output){
|
|
5
5
|
const n=320*320;
|
|
6
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
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);
|
|
8
|
+
const frames=grayFrameReader(bytes,320,320,info.pairs*9),rgba=output??new Uint8ClampedArray(n*4);
|
|
9
|
+
if(!(rgba instanceof Uint8ClampedArray)||rgba.length!==n*4)throw Error('Invalid sprite output');
|
|
10
|
+
for(let i=3;i<rgba.length;i+=4)rgba[i]=255;
|
|
9
11
|
return({clip,progress})=>{
|
|
10
12
|
const list=info.clips[clip];if(!list||!Number.isFinite(progress)||progress<0||progress>1)throw Error('Invalid companion sprite pose');
|
|
11
13
|
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);
|
|
@@ -80,7 +80,7 @@ function unfilterRow(type,src,at,cur,prev,w){
|
|
|
80
80
|
|
|
81
81
|
// Validate and unfilter. Only the returned typed arrays survive; `bytes` is
|
|
82
82
|
// not referenced by the store built from them.
|
|
83
|
-
function decode(bytes){
|
|
83
|
+
function decode(bytes,{frameIndices}={}){
|
|
84
84
|
if(!(bytes instanceof Uint8Array))fail('bytes');
|
|
85
85
|
if(!isPredictiveFrames(bytes)||bytes.length<HEADER)fail('magic');
|
|
86
86
|
const view=new DataView(bytes.buffer,bytes.byteOffset,bytes.byteLength),u32=at=>view.getUint32(at,true);
|
|
@@ -89,8 +89,13 @@ function decode(bytes){
|
|
|
89
89
|
if(unique<1||unique>frameCount)fail('unique count');
|
|
90
90
|
const data=HEADER+4*frameCount+RECORD*unique;
|
|
91
91
|
if(bytes.length<data)fail('truncated');
|
|
92
|
-
const
|
|
93
|
-
|
|
92
|
+
const retained=frameIndices===undefined?null:new Uint8Array(frameCount);
|
|
93
|
+
if(retained){
|
|
94
|
+
if(!Array.isArray(frameIndices)||!frameIndices.length)fail('retained frames');
|
|
95
|
+
for(const f of frameIndices){if(!Number.isInteger(f)||f<0||f>=frameCount)fail('retained frame index');retained[f]=1;}
|
|
96
|
+
}
|
|
97
|
+
const map=new Uint32Array(frameCount),used=new Uint8Array(unique),needed=retained?new Uint8Array(unique):null;
|
|
98
|
+
for(let f=0;f<frameCount;f++){const u=u32(HEADER+4*f);if(u>=unique)fail('map');map[f]=u;used[u]=1;if(retained?.[f])needed[u]=1;}
|
|
94
99
|
if(used.includes(0))fail('unreferenced frame');
|
|
95
100
|
// x,y,w,h,first pixel index in the packed stream
|
|
96
101
|
const rects=new Float64Array(unique*5);let total=0,pixels=0;
|
|
@@ -98,7 +103,7 @@ function decode(bytes){
|
|
|
98
103
|
const at=HEADER+4*frameCount+RECORD*u,x=u32(at),y=u32(at+4),w=u32(at+8),h=u32(at+12),offset=u32(at+16),length=u32(at+20);
|
|
99
104
|
if((w===0)!==(h===0)||(w===0&&(x||y))||x+w>width||y+h>height)fail('rectangle');
|
|
100
105
|
if(length!==h*(w+1)||offset!==total)fail('offset');
|
|
101
|
-
rects.set([x,y,w,h,pixels],u*5);total+=length;pixels+=w*h;
|
|
106
|
+
rects.set([x,y,w,h,pixels],u*5);total+=length;if(!needed||needed[u])pixels+=w*h;
|
|
102
107
|
}
|
|
103
108
|
if(bytes.length!==data+total)fail('pixel length');
|
|
104
109
|
if(pixels*BITS>0xffffffff)fail('pixel count');
|
|
@@ -109,23 +114,24 @@ function decode(bytes){
|
|
|
109
114
|
for(let y=0;y<h;y++){
|
|
110
115
|
unfilterRow(bytes[at],bytes,at+1,cur,prev,w);at+=w+1;
|
|
111
116
|
for(let x=0;x<w;x++){
|
|
112
|
-
const q=cur[x];if(q>31)fail('quantized value');
|
|
117
|
+
const q=cur[x];if(q>31)fail('quantized value');if(needed&&!needed[u])continue;
|
|
113
118
|
const i=pos>>>3,s=pos&7;packed[i]|=(q<<s)&255;if(s>3)packed[i+1]|=q>>(8-s);pos+=BITS;
|
|
114
119
|
}
|
|
115
120
|
const t=prev;prev=cur;cur=t;
|
|
116
121
|
}
|
|
117
122
|
}
|
|
118
|
-
return{width,height,frameCount,unique,map,rects,packed};
|
|
123
|
+
return{width,height,frameCount,unique,map,rects,packed,retained};
|
|
119
124
|
}
|
|
120
125
|
|
|
121
|
-
function createStore({width,height,frameCount,unique,map,rects,packed}){
|
|
126
|
+
function createStore({width,height,frameCount,unique,map,rects,packed,retained}){
|
|
122
127
|
const n=width*height,slots=[{unique:-1,frame:null},{unique:-1,frame:null}];let decodes=0,hits=0;
|
|
123
128
|
return Object.freeze({
|
|
124
129
|
width,height,frameCount,uniqueCount:unique,byteLength:n*frameCount,residentPixelBytes:packed.byteLength,
|
|
125
|
-
get residentBytes(){return packed.byteLength+map.byteLength+rects.byteLength+slots.reduce((s,e)=>s+(e.frame?.byteLength??0),0);},
|
|
130
|
+
get residentBytes(){return packed.byteLength+map.byteLength+rects.byteLength+(retained?.byteLength??0)+slots.reduce((s,e)=>s+(e.frame?.byteLength??0),0);},
|
|
126
131
|
stats(){return{decodes,hits,cachedFrames:slots.filter(e=>e.frame).length};},
|
|
127
132
|
getFrame(index){
|
|
128
133
|
if(!Number.isInteger(index)||index<0||index>=frameCount)fail('frame index');
|
|
134
|
+
if(retained&&!retained[index])fail('frame was not retained');
|
|
129
135
|
const u=map[index];
|
|
130
136
|
if(slots[0].unique===u){hits++;return slots[0].frame;}
|
|
131
137
|
if(slots[1].unique===u){hits++;slots.reverse();return slots[0].frame;}
|
|
@@ -144,4 +150,4 @@ function createStore({width,height,frameCount,unique,map,rects,packed}){
|
|
|
144
150
|
|
|
145
151
|
// Parse, validate and unpack an RVQ5 store. A returned frame is valid until two
|
|
146
152
|
// other unique frames have been requested.
|
|
147
|
-
export function readPredictiveFrames(bytes){return createStore(decode(bytes));}
|
|
153
|
+
export function readPredictiveFrames(bytes,options){return createStore(decode(bytes,options));}
|
package/puppy-frame-store.mjs
CHANGED
|
@@ -52,9 +52,9 @@ function checkShape(width,height,frameCount){
|
|
|
52
52
|
// resident (crops only) and reconstructs at most two full frames at a time.
|
|
53
53
|
// A returned frame is valid until two other unique frames have been requested.
|
|
54
54
|
// An 'RVQ5' store (lossy 32-level comparison codec) is delegated and branded.
|
|
55
|
-
export function readPackedFrames(bytes){
|
|
55
|
+
export function readPackedFrames(bytes,options){
|
|
56
56
|
if(!(bytes instanceof Uint8Array))throw Error('Invalid packed frames: bytes');
|
|
57
|
-
if(isPredictiveFrames(bytes)){const store=readPredictiveFrames(bytes);stores.add(store);return store;}
|
|
57
|
+
if(isPredictiveFrames(bytes)){const store=readPredictiveFrames(bytes,options);stores.add(store);return store;}
|
|
58
58
|
if(bytes.length<HEADER||MAGIC.some((v,i)=>bytes[i]!==v))throw Error('Invalid packed frames: magic');
|
|
59
59
|
const view=new DataView(bytes.buffer,bytes.byteOffset,bytes.byteLength),u32=at=>view.getUint32(at,true);
|
|
60
60
|
const width=u32(4),height=u32(8),frameCount=u32(12),unique=u32(16);
|
package/puppy-paper-actions.mjs
CHANGED
|
@@ -37,11 +37,13 @@ export function paperActionPose(name,progress,info){
|
|
|
37
37
|
if(!Number.isFinite(blend))throw Error('Invalid paper action: blend');
|
|
38
38
|
return{pair:list[index],blend};
|
|
39
39
|
}
|
|
40
|
-
export function createPaperActionSampler(bytes,info){
|
|
40
|
+
export function createPaperActionSampler(bytes,info,output){
|
|
41
41
|
if(!isGrayFrameSource(bytes))throw Error('Invalid action cache: bytes');
|
|
42
42
|
validatePaperActionInfo(info,bytes.byteLength);
|
|
43
43
|
const stride=info.width*info.height,pairs=info.pairs,frames=grayFrameReader(bytes,info.width,info.height,pairs*9);
|
|
44
|
-
const out=new Uint8ClampedArray(stride*4);
|
|
44
|
+
const out=output??new Uint8ClampedArray(stride*4);
|
|
45
|
+
if(!(out instanceof Uint8ClampedArray)||out.length!==stride*4)throw Error('Invalid action output');
|
|
46
|
+
for(let i=3;i<out.length;i+=4)out[i]=255;
|
|
45
47
|
return state=>{const p=paperActionPose(state.actionName,state.actionProgress,info),sample=Math.round(p.blend*8);
|
|
46
48
|
if(p.pair>=pairs||sample<0||sample>8)throw Error('Invalid paper action: sample out of range');
|
|
47
49
|
const frame=frames.getFrame(p.pair*9+sample);for(let i=0,j=0;i<stride;i++,j+=4)out[j]=out[j+1]=out[j+2]=frame[i];return out;};
|
|
@@ -5,4 +5,4 @@ export function paperBehaviorPose(state,info){
|
|
|
5
5
|
const q=Math.min(list.length-1e-9,progress*list.length),i=Math.floor(q),blend=Math.round((q-i)*8)/8;
|
|
6
6
|
return{pair:list[i],blend};
|
|
7
7
|
}
|
|
8
|
-
export function createPaperBehaviorSampler(bytes,info){const sample=createRearSampler(bytes,info);return state=>{const p=paperBehaviorPose(state,info);return sample(p.pair,p.blend);};}
|
|
8
|
+
export function createPaperBehaviorSampler(bytes,info,output){const sample=createRearSampler(bytes,info,output);return state=>{const p=paperBehaviorPose(state,info);return sample(p.pair,p.blend);};}
|
package/puppy-paper-contact.mjs
CHANGED
|
@@ -91,9 +91,11 @@ export function footSourcePoint(x,y,pins){
|
|
|
91
91
|
return chosen?{x:x-chosen.dx*best,y:y-chosen.dy*best}:{x,y};
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
export function createRearSampler(bytes,info){
|
|
94
|
+
export function createRearSampler(bytes,info,output){
|
|
95
95
|
if(!isGrayFrameSource(bytes)||info.pairs!==18||info.samples!==9||bytes.byteLength!==18*9*320*320)throw Error('Invalid rear sprite cache');
|
|
96
|
-
const frames=grayFrameReader(bytes,320,320,18*9),out=new Uint8ClampedArray(320*320*4);
|
|
96
|
+
const frames=grayFrameReader(bytes,320,320,18*9),out=output??new Uint8ClampedArray(320*320*4);
|
|
97
|
+
if(!(out instanceof Uint8ClampedArray)||out.length!==320*320*4)throw Error('Invalid rear output');
|
|
98
|
+
for(let i=3;i<out.length;i+=4)out[i]=255;
|
|
97
99
|
return(pair,blend)=>{
|
|
98
100
|
if(!Number.isInteger(pair)||pair<0||pair>=18||!Number.isFinite(blend)||blend<0||blend>1)throw Error('Invalid rear pose');
|
|
99
101
|
const frame=frames.getFrame(pair*9+Math.round(blend*8));
|
package/puppy-paper-seat.mjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {grayFrameReader,isGrayFrameSource} from './puppy-frame-store.mjs';
|
|
2
2
|
// Exact cached samples; no live crossfade. Reverse the same path to stand up.
|
|
3
|
-
export function createPaperSeatSampler(bytes,info){
|
|
3
|
+
export function createPaperSeatSampler(bytes,info,output){
|
|
4
4
|
const stride=320*320;
|
|
5
5
|
if(!isGrayFrameSource(bytes)||info.width!==320||info.height!==320||info.pairs!==3||info.samples!==17||bytes.byteLength!==3*17*stride)throw Error('Invalid paper sitting cache');
|
|
6
|
-
const frames=grayFrameReader(bytes,320,320,3*17),out=new Uint8ClampedArray(stride*4);
|
|
6
|
+
const frames=grayFrameReader(bytes,320,320,3*17),out=output??new Uint8ClampedArray(stride*4);
|
|
7
|
+
if(!(out instanceof Uint8ClampedArray)||out.length!==stride*4)throw Error('Invalid seat output');
|
|
8
|
+
for(let i=3;i<out.length;i+=4)out[i]=255;
|
|
7
9
|
return progress=>{
|
|
8
10
|
if(!Number.isFinite(progress)||progress<0||progress>1)throw Error('Invalid paper sitting progress');
|
|
9
11
|
const q=progress*3,pair=Math.min(2,Math.floor(q)),sample=Math.round((q-pair)*16),frame=frames.getFrame(pair*17+sample);
|
package/puppy-paper-world.mjs
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
// Design calibration, not a measurement of the user's current head position.
|
|
2
2
|
// Sources: OpenCV pinhole model; PsychoPy viewtools physical-screen frustums.
|
|
3
3
|
const diagonal=.0254*32;
|
|
4
|
+
// The paper actor already integrates its own calibrated travel profile and foot
|
|
5
|
+
// contacts. Its old 3D Animal.follow() merely copied that root's x/z, then also
|
|
6
|
+
// updated an invisible skinned mesh, IK, fur and materials. Keep just the follow
|
|
7
|
+
// contract here; speed/stride/projection remain owned by the existing planner.
|
|
8
|
+
export function createPaperBody(){
|
|
9
|
+
const position={x:0,y:0,z:0};let target=null,disposed=false;
|
|
10
|
+
const alive=()=>{if(disposed)throw Error('Paper body is disposed');};
|
|
11
|
+
return{
|
|
12
|
+
position,
|
|
13
|
+
follow(point){alive();if(!point||![point.x,point.y,point.z].every(Number.isFinite))throw Error('Invalid paper body position');target={x:point.x,y:point.y,z:point.z};},
|
|
14
|
+
update(dt){alive();if(!Number.isFinite(dt)||dt<0||dt>.1)throw Error('Invalid paper body step');if(target){position.x=target.x;position.z=target.z;}},
|
|
15
|
+
dispose(){disposed=true;target=null;},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
4
18
|
export const PAPER_SCREEN=Object.freeze({widthMeters:diagonal*16/Math.hypot(16,9),heightMeters:diagonal*9/Math.hypot(16,9),viewDistance:.70});
|
|
5
19
|
const eyeHeight=.45,eyeZ=1.65,pitch=9*Math.PI/180;
|
|
6
20
|
export const PAPER_CAMERA=Object.freeze({fov:2*Math.atan(PAPER_SCREEN.heightMeters/(2*PAPER_SCREEN.viewDistance))*180/Math.PI,aspect:16/9,position:Object.freeze([0,eyeHeight,eyeZ]),target:Object.freeze([0,.12,eyeZ-(eyeHeight-.12)/Math.tan(pitch)]),canvasMeters:.64});
|