@bitefoundry/retrieviewer 0.0.11 → 0.0.12
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/MOTION-TABLES.md +61 -0
- package/RELEASING.md +19 -1
- package/package.json +7 -2
- package/puppy-motion-lookup.mjs +20 -0
- package/puppy-motion-tables.generated.mjs +4 -0
- package/puppy-paper-actions.mjs +5 -4
- package/puppy-paper-contact.mjs +10 -0
- package/puppy-paper.mjs +30 -16
- package/retrieviewer.mjs +6 -2
package/MOTION-TABLES.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Precomputed motion tables (0.0.12)
|
|
2
|
+
|
|
3
|
+
`npm run bake:motion` compiles the current approved sources into
|
|
4
|
+
`puppy-motion-tables.generated.mjs`. It does not change a picture, camera,
|
|
5
|
+
trajectory, animation duration or source metadata. `npm run check:motion` checks
|
|
6
|
+
the exact deterministic output without writing. Tests and the publication guard
|
|
7
|
+
reject stale output after source metadata or witnessed art changes.
|
|
8
|
+
|
|
9
|
+
## What is precomputed
|
|
10
|
+
|
|
11
|
+
- Source support episodes, including continuous stance across a cycle seam and
|
|
12
|
+
a complete swing skipped between rendered frames. No stance-history discovery
|
|
13
|
+
occurs while building a default renderer, including after a resize.
|
|
14
|
+
- Clip lists, weights and totals used for action-pose addressing. The runtime no
|
|
15
|
+
longer validates/rebuilds these same lists and totals for each default pose.
|
|
16
|
+
- A dense table of72 facing/seat preparation cases, sharing8 step descriptors.
|
|
17
|
+
Lookup requires a stationary root; it does not insert a turn at running speed.
|
|
18
|
+
- Ten exact-pixel connection witnesses with view, speed and (where applicable)
|
|
19
|
+
gait-phase/velocity-match requirements. These cover walk entry/exit, rear run
|
|
20
|
+
into the authored impact, impact into rear pickup, carry-gather into arrival
|
|
21
|
+
seat, tug into the canonical seat, and four watch endpoints into that seat.
|
|
22
|
+
- SHA256 of every input metadata/art file used by the bake. No source images,
|
|
23
|
+
source hashes or graph search are computed by the running pet.
|
|
24
|
+
|
|
25
|
+
The generated routes preserve the existing approved preparation order. This is
|
|
26
|
+
a bounded compilation of existing paths, not unrestricted motion matching or a
|
|
27
|
+
new animation blend engine. Other actor-specific recovery rules stay in place.
|
|
28
|
+
Unregistered arbitrary-phase joins are not certified: in particular an urgently
|
|
29
|
+
interrupted walk may use its existing recovery rather than a proven phase0 join.
|
|
30
|
+
|
|
31
|
+
## What remains dynamic
|
|
32
|
+
|
|
33
|
+
World displacement, actual velocity, unwrapped gait phase, perspective and the
|
|
34
|
+
small paw-to-world anchor correction still depend on live state. Those cannot
|
|
35
|
+
be baked as fixed screen coordinates while allowing free travel and resizing.
|
|
36
|
+
Support tables address the original source coordinates; they do not stretch the
|
|
37
|
+
head/torso, replace drawings or cause a camera orbit.
|
|
38
|
+
|
|
39
|
+
Paw labels are visible image-space proxies, not anatomical motion capture. Some
|
|
40
|
+
resting endpoints have exact-pose evidence but no individually labeled paws.
|
|
41
|
+
The authored run-to-impact entry is **airborne**, not a planted-paw handoff:
|
|
42
|
+
its gate requires the correct phase, positive speed and matched velocity.
|
|
43
|
+
Neither exact pixels nor a green numerical test proves general animal realism.
|
|
44
|
+
|
|
45
|
+
## Compatibility and resource scope
|
|
46
|
+
|
|
47
|
+
The bundled Q5/default-loader path uses the compiled tables. Optional original
|
|
48
|
+
art and custom loaders retain the general metadata-driven implementation instead
|
|
49
|
+
of accidentally applying the bundled pet's bake to unrelated art. The general
|
|
50
|
+
helpers remain available for authoring and equivalence tests.
|
|
51
|
+
|
|
52
|
+
The generated module is about11KB source, shared between instances; there is no
|
|
53
|
+
extra image cache, dependency, timer, worker or asset-fetch round trip. It removes
|
|
54
|
+
repeat discovery/allocation work, not the roughly20MB retained image payload or
|
|
55
|
+
Node/native process baseline. It is not a large-RAM-reduction claim.
|
|
56
|
+
|
|
57
|
+
Verification compares every baked support sample and wrap, all action-addressing
|
|
58
|
+
boundaries, both actor paths through seeded fetches and rare impacts, and the
|
|
59
|
+
public renderer's text, contacts and mouth anchors. Use
|
|
60
|
+
`node --test puppy-motion-tables.test.mjs`. The owner authorized publication of
|
|
61
|
+
this work as0.0.12 on2026-10-24. Earlier published artifacts remain unchanged.
|
package/RELEASING.md
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
# Retrieviewer 0.0.
|
|
1
|
+
# Retrieviewer 0.0.12 release process
|
|
2
|
+
|
|
3
|
+
Current target: `@bitefoundry/retrieviewer@0.0.12`, public `latest`.
|
|
4
|
+
On2026-10-24 the owner authorized npm publication and website deployment of the
|
|
5
|
+
reviewed precomputed motion tables. Support episodes, action addressing and
|
|
6
|
+
bounded preparation routes are compiled offline; live travel, perspective and
|
|
7
|
+
paw correction remain dynamic. Default Q5 uses the tables; custom loaders and
|
|
8
|
+
optional original art retain their metadata-driven path. See MOTION-TABLES.md.
|
|
9
|
+
No new artwork, runtime dependency, process or timer. This removes repeated
|
|
10
|
+
CPU/allocation work, not the retained image payload or Node/native baseline.
|
|
11
|
+
Do not claim a large RAM reduction or new Linux/macOS live GUI certification.
|
|
12
|
+
|
|
13
|
+
Build and verify a fresh exact0.0.12 tarball outside the source tree, including
|
|
14
|
+
its owned Windows native lifecycle and bilingual browser runtime. Publish that
|
|
15
|
+
same tarball, verify registry integrity and matching GitHub Pages runtime bytes.
|
|
16
|
+
Do not restart the user's live pet or change host/agent configuration. Earlier
|
|
17
|
+
npm artifacts remain immutable; MIT code / CC BY-SA4.0 artwork stay unchanged.
|
|
18
|
+
|
|
19
|
+
## Previous 0.0.11 scope (historical)
|
|
2
20
|
|
|
3
21
|
Current target: `@bitefoundry/retrieviewer@0.0.11`, public `latest`.
|
|
4
22
|
On2026-10-24 the owner accepted the reviewed candidate and authorized immediate
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitefoundry/retrieviewer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
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
6
|
"homepage": "https://bitefoundry.github.io/retrieviewer/",
|
|
@@ -90,6 +90,7 @@
|
|
|
90
90
|
"PUPPY-Q5-COMPARISON.md",
|
|
91
91
|
"COMFORT-ART.md",
|
|
92
92
|
"WATCH-REDRAW.md",
|
|
93
|
+
"MOTION-TABLES.md",
|
|
93
94
|
"BUTTERFLY.md",
|
|
94
95
|
"examples/embed.mjs",
|
|
95
96
|
"examples/live.mjs",
|
|
@@ -102,6 +103,8 @@
|
|
|
102
103
|
"puppy-paper.mjs",
|
|
103
104
|
"puppy-paper-world.mjs",
|
|
104
105
|
"puppy-paper-contact.mjs",
|
|
106
|
+
"puppy-motion-lookup.mjs",
|
|
107
|
+
"puppy-motion-tables.generated.mjs",
|
|
105
108
|
"puppy-paper-seat.mjs",
|
|
106
109
|
"puppy-paper-director.mjs",
|
|
107
110
|
"puppy-paper-behaviors.mjs",
|
|
@@ -144,13 +147,15 @@
|
|
|
144
147
|
"vendor/procedural-animals/LICENSE"
|
|
145
148
|
],
|
|
146
149
|
"scripts": {
|
|
150
|
+
"bake:motion": "node tools/bake-pet-motion.mjs",
|
|
151
|
+
"check:motion": "node tools/bake-pet-motion.mjs --check",
|
|
147
152
|
"start": "node tools/preview-site.mjs",
|
|
148
153
|
"build:site": "node tools/build-site.mjs",
|
|
149
154
|
"pet:companion": "node examples/live.mjs",
|
|
150
155
|
"pet:desktop": "node retrieviewer-cli.mjs desktop",
|
|
151
156
|
"test": "node --test \"*.test.mjs\"",
|
|
152
157
|
"test:package": "node check-pet-package.mjs",
|
|
153
|
-
"release:check": "node tools/check-release.mjs",
|
|
158
|
+
"release:check": "npm run check:motion && node tools/check-release.mjs",
|
|
154
159
|
"prepublishOnly": "npm run release:check"
|
|
155
160
|
},
|
|
156
161
|
"dependencies": {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Pure lookups over offline data. No source analysis, graph search or I/O here.
|
|
2
|
+
const views=Object.freeze({front:0,rear:1,approach:2});
|
|
3
|
+
export function preparationRoute(tables,kind,{view,flip,seatProgress=0,desired,nextFlip=false,speed=0}){
|
|
4
|
+
if(!Number.isFinite(speed)||Math.abs(speed)>tables.routes.maxPreparationSpeed)throw Error('Motion preparation requires a stopped root');
|
|
5
|
+
const viewIndex=views[view],seat=seatProgress===0?0:seatProgress===1?2:1;
|
|
6
|
+
const target=kind==='action'?(desired==='stand'?0:desired==='seat'?1:undefined):views[desired];
|
|
7
|
+
if(viewIndex===undefined||target===undefined||typeof flip!=='boolean'||typeof nextFlip!=='boolean')throw Error('Unknown baked motion route');
|
|
8
|
+
const index=kind==='action'?((viewIndex*2+ +flip)*3+seat)*2+target:((viewIndex*2+ +flip)*3+target)*2+ +nextFlip;
|
|
9
|
+
const code=tables.routes[kind]?.[index],route=tables.routes.steps[code];if(!route)throw Error('Unknown baked motion route');
|
|
10
|
+
return route;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function canJoinMotion(tables,name,{view,speed,phase=0,nextSpeed=speed}){
|
|
14
|
+
const join=tables.joins[name],epsilon=1e-7;
|
|
15
|
+
if(!join||join.view!==view||![speed,phase,nextSpeed].every(Number.isFinite))return false;
|
|
16
|
+
if(speed<join.speed[0]-epsilon||speed>join.speed[1]+epsilon||nextSpeed<join.speed[0]-epsilon||nextSpeed>join.speed[1]+epsilon||join.positiveSpeed&&(speed<=0||nextSpeed<=0))return false;
|
|
17
|
+
if(join.phase!==undefined){const d=phase-join.phase;if(Math.abs(d-Math.round(d))>epsilon)return false;}
|
|
18
|
+
if(join.matchVelocity&&Math.abs(speed-nextSpeed)>epsilon)return false;
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Generated by tools/bake-pet-motion.mjs. Do not edit by hand.
|
|
2
|
+
// Source paw labels are image-space proxies, not anatomical motion capture.
|
|
3
|
+
const freeze=v=>{if(v&&typeof v==='object'){for(const x of Object.values(v))freeze(x);Object.freeze(v);}return v;};
|
|
4
|
+
export const BAKED_MOTION=freeze({"version":1,"sources":{"puppy-stride-meta.json":"21725d593d9a38ea59f68e359ef85c1d1569990155bf74a0ee7c1c111fb4f9c8","puppy-paper-rear-gallop.json":"d31c7487dcf144ea14323e13ad2e5009ab577431629f983dae1d17f268a4bb8c","puppy-paper-approach.json":"15b1e829e4d2cf76cfdb1a6a0ad27c7e916ccba46ca2879a96acf98d23c90855","puppy-paper-actions-v9.json":"010b3f4eb8e29b36f13cea460e5de424a1a0d25863633df40418d1d820a19a01","puppy-paper-behaviors.json":"c1bd1a01b2c652d0cad6c994be2b92b2c0927a1f808e66f5e1efa8890f61da7a","puppy-companion-comfort.json":"5234cf9566957c91ad0aa76c5dae4c9449f6c34171dcb581bf6d114b607c4a18","puppy-paper-actions-v9-q5.bin.gz":"abb4677468206c62937c0247dc4c5823e0a7c4a3a197da40194a08dd594aeef9","puppy-paper-rear-gallop-q5.bin.gz":"ca731e1979a37ec2e005a80365e3b58358f640b8b26e7036b0e931940a7b1264","puppy-companion-comfort-q5.bin.gz":"9f8c89bf4764eb2f1f17131e2413d941f1eae33ae9a15ffbe76cc33f2d18103a","puppy-paper-arrival-seat-q5.bin.gz":"7effa0a2150e8ef9ed37d5b6cb10089672e0ce32599c06db21ad4769144bf246","puppy-paper-seat-q5.bin.gz":"5480c994de0d034d70eff6ea86095f3722cf87bde72f364dd369b94b1ad66f84","puppy-paper-behaviors-q5.bin.gz":"e4b79387aca974ceec74a02dc3f02780eb53d38af6ec9ebd69994de744b39716"},"support":{"front":{"step":16,"period":128,"cyclic":true,"offsets":{"0":0,"1":16,"2":32,"3":48,"4":64,"5":80,"6":96,"7":112},"starts":{"hind-near":[123,123,123,123,123,123,123,123,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,123,123,123,123,123],"fore-far":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],"fore-near":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],"hind-far":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]}},"rear":{"step":8,"period":64,"cyclic":true,"offsets":{"5":0,"6":8,"7":16,"8":24,"9":32,"10":40,"11":48,"12":56},"starts":{"hind-far":[60,60,60,60,60,60,60,60,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,60,60,60,60],"hind-near":[62,62,62,62,62,62,62,62,62,62,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,62]}},"approach":{"step":8,"period":64,"cyclic":true,"offsets":{"5":0,"6":8,"7":16,"8":24,"9":32,"10":40,"11":48,"12":56},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,39,39,39,39,39,39,-1,-1,-1,-1,-1,-1,-1,-1,-1,54,54,54,54,54,-1,-1,-1,-1,-1],"fore-right":[61,61,61,61,61,61,61,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,-1,-1,-1,-1,55,55,55,55,55,-1,61,61,61]}},"walk":{"step":8,"period":64,"cyclic":true,"offsets":{"42":0,"43":8,"44":16,"45":24,"46":32,"47":40,"48":48,"49":56},"starts":{"hind-far":[52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,52,52,52,52,52,52,52,52,52,52,52,52],"hind-near":[58,58,58,58,58,58,58,58,58,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,24,24,24,24,24,24,24,24,24,24,24,24,24,24,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,58,58,58,58,58,58],"fore-far":[-1,-1,-1,3,3,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,21,21,21,21,21,-1,-1,-1,-1,-1,31,31,31,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,47,47,47,47,47,-1,-1,-1,-1,-1,-1,-1,59,59,59,-1,-1],"fore-near":[-1,-1,-1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,-1,-1,-1,-1,-1,-1,-1,33,-1,-1,-1,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,-1,-1]}},"behavior/walk":{"step":8,"period":32,"cyclic":true,"offsets":{"0":0,"1":8,"2":16,"3":24},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,24,24,-1,-1,-1,-1,-1,-1],"fore-right":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]}},"behavior/walk-enter":{"step":8,"period":8,"cyclic":false,"offsets":{"4":0},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1],"fore-right":[-1,-1,-1,-1,4,4,4,4,4]}},"behavior/brake":{"step":8,"period":32,"cyclic":false,"offsets":{"5":0,"6":8,"7":16,"8":24},"starts":{"fore-left":[-1,-1,-1,-1,-1,-1,-1,-1,-1,9,9,9,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,23,23,23,23,23,23,23,23,23,23],"fore-right":[0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,15,15,15,15,15,15,15,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]}},"behavior/finish":{"step":8,"period":8,"cyclic":false,"offsets":{"9":0},"starts":{}},"behavior/watch-left":{"step":8,"period":16,"cyclic":false,"offsets":{"10":0,"11":8},"starts":{}},"behavior/watch-right":{"step":8,"period":16,"cyclic":false,"offsets":{"12":0,"13":8},"starts":{}},"behavior/rest":{"step":8,"period":32,"cyclic":false,"offsets":{"14":0,"15":8,"16":16,"17":24},"starts":{}}},"actionClips":{"spin":{"list":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],"weights":[1.1168,0.8052,0.827,0.7936,1.3421,1.4204,0.9015,0.5275,1.1081,0.7701,0.723,1.0494,1.4422,1.3325,1.0787,0.8964,0.8655],"total":17},"roll":{"list":[17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"weights":[1.122,1.4089,1.6479,0.6752,0.753,0.8756,0.9957,0.9586,0.7325,0.8218,1.0968,0.9962,0.8959,0.6589,1.0191,0.8352,0.4557,1.1818,1.1101,0.905,0.6752,1.6479,1.4089,1.122],"total":23.9999},"roll-down":{"list":[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"weights":[1.6886,0.6919,0.7717,0.8973,1.0203,0.9823,0.7506,0.8422,1.124,1.0208,0.918,0.6752,1.0443,0.8559,0.467,1.211,1.1376,0.9274,0.6919,1.6886,1.4438,1.1498],"total":22.0002},"lie-down":{"list":[17,18],"weights":[0.8866,1.1134],"total":2},"lie-up":{"list":[39,40],"weights":[1.1134,0.8866],"total":2},"walk-enter":{"list":[41],"weights":[1],"total":1},"walk":{"list":[42,43,44,45,46,47,48,49],"weights":[1,1,1,1,1,1,1,1],"total":8},"walk-exit":{"list":[50],"weights":[1],"total":1},"walk-face-front":{"list":[51],"weights":[1],"total":1},"walk-face-rear":{"list":[52],"weights":[1],"total":1},"walk-turn":{"list":[53,54,55,56,57,58,59,60,61,62,63,64,65],"weights":[1,1,1,1,1,1,1,1,1,1,1,1,1],"total":13}},"routes":{"maxPreparationSpeed":1e-8,"steps":[["ready"],["turn",true],["view-turn","rear"],["view-turn","approach"],["turn",false],["view-turn","front"],["rise"],["sit-down"]],"direction":[0,1,2,2,3,3,4,0,2,2,3,3,5,5,0,0,5,5,5,5,0,0,5,5,5,5,5,5,0,0,5,5,5,5,0,0],"action":[0,3,6,3,6,3,4,4,6,4,6,4,5,5,6,5,6,5,5,5,6,5,6,5,5,7,6,7,6,0,5,5,6,5,6,5]},"joins":{"walk-enter/walk":{"from":["puppy-paper-actions-v9",377],"to":["puppy-paper-actions-v9",378],"poseSha256":"81361614df56226b64be437f189c2e135c13498324286880db0fc06c5df3e86a","view":"front","speed":[0,0],"supportEvidence":"shared-pixels-with-labeled-walk-pose","supports":["hind-far","hind-near"],"phase":0},"walk/walk-exit":{"from":["puppy-paper-actions-v9",449],"to":["puppy-paper-actions-v9",450],"poseSha256":"81361614df56226b64be437f189c2e135c13498324286880db0fc06c5df3e86a","view":"front","speed":[0,0],"supportEvidence":"shared-pixels-with-labeled-walk-pose","supports":["hind-far","hind-near"],"phase":0},"rear-run/scramble":{"from":["puppy-paper-rear-gallop",63],"to":["puppy-companion-comfort",25],"poseSha256":"fa79a8762b57c0d5b70586a687f10e4a313e227e11e2435f6d7af0cd0866cc83","view":"rear","phase":0.25,"speed":[0,4.556913271064087],"positiveSpeed":true,"matchVelocity":true,"supports":[],"supportEvidence":"source-paw-proxies","airborne":true},"scramble/pickup-rear":{"from":["puppy-companion-comfort",36],"to":["puppy-companion-comfort",13],"poseSha256":"8192c504552a3984c80e1c3216e134605d4a930ec14cd7f778036e629e334601","view":"rear","speed":[0,0],"supports":["hind-far","hind-near"],"supportEvidence":"shared-pixels-with-labeled-rear-pose"},"carry-settle/arrival-seat":{"from":["puppy-companion-comfort",44],"to":["puppy-paper-arrival-seat",0],"poseSha256":"5ccf5acd9ca9ea81a0c9fc59d1ab2a2ddab148c942e31009f1a4c18de347fae8","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"tug/seat":{"from":["puppy-companion-comfort",0],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-90/seat":{"from":["puppy-paper-behaviors",90],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-107/seat":{"from":["puppy-paper-behaviors",107],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-108/seat":{"from":["puppy-paper-behaviors",108],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"},"watch-125/seat":{"from":["puppy-paper-behaviors",125],"to":["puppy-paper-seat",50],"poseSha256":"19f89a8bcb5a937e528593a8f36db846a0d45a5ee398f1b0873c056e5be2fa0a","view":"approach","speed":[0,0],"supportEvidence":"shared-pose-only"}}});
|
package/puppy-paper-actions.mjs
CHANGED
|
@@ -28,23 +28,24 @@ export function validatePaperActionInfo(info,byteLength){
|
|
|
28
28
|
if(byteLength!==undefined&&byteLength!==f.width*f.height*f.samples*info.pairs)throw Error('Invalid action cache: byte length');
|
|
29
29
|
return info;
|
|
30
30
|
}
|
|
31
|
-
export function paperActionPose(name,progress,info){
|
|
31
|
+
export function paperActionPose(name,progress,info,compiledClips){
|
|
32
32
|
if(typeof progress!=='number'||!Number.isFinite(progress))throw Error('Invalid paper action: progress');
|
|
33
|
-
|
|
33
|
+
if(compiledClips&&!own(compiledClips,name))throw Error(`Invalid paper action: unknown compiled clip ${JSON.stringify(name)}`);
|
|
34
|
+
const{list,weights,total=weights.reduce((a,b)=>a+b,0)}=compiledClips?.[name]??actionClip(name,info);
|
|
34
35
|
let t=(name==='walk'?((progress%1)+1)%1:Math.max(0,Math.min(1,progress)))*total,index=0;
|
|
35
36
|
while(index<list.length-1&&t>weights[index]){t-=weights[index++];}
|
|
36
37
|
const blend=Math.round(Math.max(0,Math.min(1,t/weights[index]))*8)/8;
|
|
37
38
|
if(!Number.isFinite(blend))throw Error('Invalid paper action: blend');
|
|
38
39
|
return{pair:list[index],blend};
|
|
39
40
|
}
|
|
40
|
-
export function createPaperActionSampler(bytes,info,output){
|
|
41
|
+
export function createPaperActionSampler(bytes,info,output,compiledClips){
|
|
41
42
|
if(!isGrayFrameSource(bytes))throw Error('Invalid action cache: bytes');
|
|
42
43
|
validatePaperActionInfo(info,bytes.byteLength);
|
|
43
44
|
const stride=info.width*info.height,pairs=info.pairs,frames=grayFrameReader(bytes,info.width,info.height,pairs*9);
|
|
44
45
|
const out=output??new Uint8ClampedArray(stride*4);
|
|
45
46
|
if(!(out instanceof Uint8ClampedArray)||out.length!==stride*4)throw Error('Invalid action output');
|
|
46
47
|
for(let i=3;i<out.length;i+=4)out[i]=255;
|
|
47
|
-
return state=>{const p=paperActionPose(state.actionName,state.actionProgress,info),sample=Math.round(p.blend*8);
|
|
48
|
+
return state=>{const p=paperActionPose(state.actionName,state.actionProgress,info,compiledClips),sample=Math.round(p.blend*8);
|
|
48
49
|
if(p.pair>=pairs||sample<0||sample>8)throw Error('Invalid paper action: sample out of range');
|
|
49
50
|
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;};
|
|
50
51
|
}
|
package/puppy-paper-contact.mjs
CHANGED
|
@@ -77,6 +77,16 @@ export function createPaperSupportEpisodes(labels,indices,samples,{cyclic=true}=
|
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
// Compiled once from the full source schedule, shared by all default renderers.
|
|
81
|
+
// Only the current index/cycle is evaluated here; no stance scan or indexOf.
|
|
82
|
+
export function createBakedSupportEpisodes(track){
|
|
83
|
+
return(feet,pair,blend,phase)=>{
|
|
84
|
+
const offset=track.offsets[pair];if(offset===undefined)return feet;
|
|
85
|
+
const q=offset+Math.round(blend*track.step),index=track.cyclic?q%track.period:Math.min(track.period,q),cycle=track.cyclic?Math.floor(phase)+Math.floor(q/track.period):0;
|
|
86
|
+
return feet.map(foot=>{const start=track.starts[foot.id]?.[index]??-1;return{...foot,episode:`${start}/${cycle-(track.cyclic&&start>index?1:0)}`};});
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
80
90
|
// Inverse, nearest-pixel leg warp; the entire head/torso above y=225 is identity.
|
|
81
91
|
// A compact support covers both the old and new toe positions to avoid a second toe.
|
|
82
92
|
export function footSourcePoint(x,y,pins){
|
package/puppy-paper.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {createCachedTween,retimeRun,cleanGroundOffset} from './puppy-clean.mjs';
|
|
2
|
-
import {createPaperFootLock,footSourcePoint,createRearSampler,createPaperSupportEpisodes} from './puppy-paper-contact.mjs';
|
|
2
|
+
import {createPaperFootLock,footSourcePoint,createRearSampler,createPaperSupportEpisodes,createBakedSupportEpisodes} from './puppy-paper-contact.mjs';
|
|
3
|
+
import {preparationRoute,canJoinMotion} from './puppy-motion-lookup.mjs';
|
|
3
4
|
import {createPaperSeatSampler} from './puppy-paper-seat.mjs';
|
|
4
5
|
import {planPaperRun,planPaperWalk,planPaperCarry,planPaperStumble,planPaperTravel,paperWalkTarget,planPaperApproach,planPaperApproachTravel,PAPER_DYNAMICS,PAPER_GAITS,PAPER_GROUND,paperGroundTarget} from './puppy-paper-world.mjs';
|
|
5
6
|
import {createPaperDirector} from './puppy-paper-director.mjs';
|
|
@@ -37,7 +38,7 @@ export function paperWatchProgress(age){
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
// Original artwork only. Physics supplies ground travel; no procedural dog is drawn.
|
|
40
|
-
export function createPaperActor(animal,info,{manualTricks=false,trickTimings=null,walkTransitions=false,comfortTimings=PAPER_COMFORT_TIMINGS,scrambleSeconds=0,fetchMotions=null}={}){
|
|
41
|
+
export function createPaperActor(animal,info,{manualTricks=false,trickTimings=null,walkTransitions=false,comfortTimings=PAPER_COMFORT_TIMINGS,scrambleSeconds=0,fetchMotions=null,motionTables=null}={}){
|
|
41
42
|
if(!Number.isFinite(scrambleSeconds)||scrambleSeconds<0||scrambleSeconds>3)throw Error('Invalid scramble duration');
|
|
42
43
|
if(fetchMotions&&(!Number.isFinite(fetchMotions.scramble?.entryPhase)||fetchMotions.scramble.entryPhase<=0||fetchMotions.scramble.entryPhase>=1||!Number.isFinite(fetchMotions.scramble.brakeSeconds)||fetchMotions.scramble.brakeSeconds<=0||fetchMotions.scramble.brakeSeconds>scrambleSeconds||!['front','rear'].every(v=>Number.isFinite(fetchMotions.pickups?.[v]?.duration)&&fetchMotions.pickups[v].duration>0&&fetchMotions.pickups[v].duration<=3)))throw Error('Invalid fetch actor metadata');
|
|
43
44
|
if(fetchMotions?.scramble.trajectory==='single-pass-target'){
|
|
@@ -110,6 +111,7 @@ export function createPaperActor(animal,info,{manualTricks=false,trickTimings=nu
|
|
|
110
111
|
}
|
|
111
112
|
if(scrambleArmed&&fetchMotions?.scramble.trajectory==='single-pass-target'&&view===fetchMotions.scramble.entryView&&!waypoints.length){
|
|
112
113
|
const stumble=planPaperStumble(distance,fetchMotions.scramble);
|
|
114
|
+
if(motionTables&&!canJoinMotion(motionTables,'rear-run/scramble',{view,phase:stumble.entryPhase,speed:stumble.entrySpeed,nextSpeed:stumble.impactAt(0).speed}))throw Error('Unsafe baked run/impact connection');
|
|
113
115
|
Object.assign(travel,{plan:stumble.plan,stride:stumble.stride,stumble,scrambleAt:stumble.entryTime});
|
|
114
116
|
}else if(scrambleArmed&&fetchMotions&&view==='front'&&!waypoints.length&&fetchMotions.scramble.trajectory!=='single-pass-target'){
|
|
115
117
|
// Last matching forepaw contact before the endpoint. Invert the existing
|
|
@@ -123,11 +125,16 @@ export function createPaperActor(animal,info,{manualTricks=false,trickTimings=nu
|
|
|
123
125
|
const prepareAction=()=>{
|
|
124
126
|
const name=pendingAction,desired=name==='spin'?'front':'approach';
|
|
125
127
|
if(restProgress>0){enter('wake');return;}
|
|
126
|
-
if(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
if(motionTables){
|
|
129
|
+
const [step,target]=preparationRoute(motionTables,'action',{view,flip,seatProgress,desired:name==='spin'?'stand':'seat',speed:motionSpeed});
|
|
130
|
+
if(step!=='ready'){if(step==='view-turn')turnView=target;else if(step==='turn')turnFlip=target;enter(step);return;}
|
|
131
|
+
}else{
|
|
132
|
+
if(name==='spin'&&seatProgress>0){enter('rise');return;}
|
|
133
|
+
if(flip&&view!=='front'){turnView='front';enter('view-turn');return;}
|
|
134
|
+
if(flip){turnFlip=false;enter('turn');return;}
|
|
135
|
+
if(view!==desired){turnView=view==='front'?desired:'front';enter('view-turn');return;}
|
|
136
|
+
if(name!=='spin'&&seatProgress<1){enter('sit-down');return;}
|
|
137
|
+
}
|
|
131
138
|
// Spin's own cache starts at key24; prepare it once, only AFTER the standing
|
|
132
139
|
// facing change. Do not crouch before a standing turn and then crouch again.
|
|
133
140
|
if(walkTransitions&&name==='spin'&&!spinReady){spinReady=true;enter('launch');return;}
|
|
@@ -143,7 +150,13 @@ export function createPaperActor(animal,info,{manualTricks=false,trickTimings=nu
|
|
|
143
150
|
}
|
|
144
151
|
playAction(name,()=>finishTrick(name));
|
|
145
152
|
};
|
|
146
|
-
const prepareDirection=()=>{
|
|
153
|
+
const prepareDirection=()=>{
|
|
154
|
+
if(pendingAction){prepareAction();return;}if(!target){settle();return;}
|
|
155
|
+
if(motionTables){
|
|
156
|
+
const [step,targetView]=preparationRoute(motionTables,'direction',{view,flip,desired:nextView,nextFlip,speed:motionSpeed});
|
|
157
|
+
if(step==='view-turn'){turnView=targetView;enter(step);}else if(step==='turn'){turnFlip=targetView;enter(step);}else issue();
|
|
158
|
+
}else if(nextView!==view){turnView=view==='front'?nextView:'front';enter('view-turn');}else if(view==='front'&&nextFlip!==flip){turnFlip=nextFlip;enter('turn');}else issue();
|
|
159
|
+
};
|
|
147
160
|
const requestAction=(name,{urgent=false}={})=>{
|
|
148
161
|
preparationRate=urgent?3:1;
|
|
149
162
|
if(name==='roll'&&manualDown&&state==='down'){route=false;target=null;waypoints=[];pendingAction=null;stayDown=false;manualDown=false;restProgress=0;playAction('roll-down',()=>finishTrick('roll'));return true;}
|
|
@@ -333,7 +346,7 @@ export function createPaperActor(animal,info,{manualTricks=false,trickTimings=nu
|
|
|
333
346
|
};
|
|
334
347
|
}
|
|
335
348
|
|
|
336
|
-
export function createPaperRenderer(cache,info,meta,width,height,{rear,approach,seat,arrivalSeat,behaviors,actions,interactions,comfort,contacts=true,pawTransport=false}={}){
|
|
349
|
+
export function createPaperRenderer(cache,info,meta,width,height,{rear,approach,seat,arrivalSeat,behaviors,actions,interactions,comfort,contacts=true,pawTransport=false,motionTables=null}={}){
|
|
337
350
|
if(![width,height].every(Number.isInteger)||width<2||height<2||width*height>1_000_000)throw Error('Invalid paper grid');
|
|
338
351
|
const tween=createCachedTween(cache,info),renderMeta={...meta,pairs:info.pair_map,run_sequence:info.run_sequence};
|
|
339
352
|
const out=new Uint8ClampedArray(width*height*4),area=createPaperAreaSampler();
|
|
@@ -350,14 +363,15 @@ export function createPaperRenderer(cache,info,meta,width,height,{rear,approach,
|
|
|
350
363
|
const behaviorSample=behaviors?createPaperBehaviorSampler(behaviors.bytes,behaviors.info,spriteScratch):null;
|
|
351
364
|
const interactionSample=interactions?createCompanionSpriteSampler(interactions.bytes,interactions.info,spriteScratch):null;
|
|
352
365
|
const comfortSample=comfort?createComfortSpriteSampler(comfort.bytes,comfort.info,spriteScratch):null;
|
|
353
|
-
const actionSample=actions?createPaperActionSampler(actions.bytes,actions.info,actionScratch.subarray(0,actions.info.width*actions.info.height*4)):null,actionArea=actions?createPaperAreaSampler(actions.info.width):null;
|
|
354
|
-
const
|
|
366
|
+
const actionSample=actions?createPaperActionSampler(actions.bytes,actions.info,actionScratch.subarray(0,actions.info.width*actions.info.height*4),motionTables?.actionClips):null,actionArea=actions?createPaperAreaSampler(actions.info.width):null;
|
|
367
|
+
const episodes=(key,labels,indices,samples,options)=>motionTables?.support[key]?createBakedSupportEpisodes(motionTables.support[key]):createPaperSupportEpisodes(labels,indices,samples,options);
|
|
368
|
+
const walkEpisodes=actions?episodes('walk',actions.info.feet,actions.info.clips.walk,9):null;
|
|
355
369
|
const sourceEpisodes=rear?{
|
|
356
|
-
front:
|
|
357
|
-
rear:
|
|
358
|
-
approach:approach?
|
|
370
|
+
front:episodes('front',rear.info.frontFeet,[0,1,2,3,4,5,6,7],17),
|
|
371
|
+
rear:episodes('rear',rear.info.rearFeet,[5,6,7,8,9,10,11,12],9),
|
|
372
|
+
approach:approach?episodes('approach',approach.info.feet,[5,6,7,8,9,10,11,12],9):null,
|
|
359
373
|
}:null;
|
|
360
|
-
const behaviorEpisodes=behaviors?Object.fromEntries(Object.entries(behaviors.info.clips).map(([name,indices])=>[name,
|
|
374
|
+
const behaviorEpisodes=behaviors?Object.fromEntries(Object.entries(behaviors.info.clips).map(([name,indices])=>[name,episodes('behavior/'+name,behaviors.info.feet,indices,9,{cyclic:name==='walk'})])):{};
|
|
361
375
|
const render=(state,{x=.5,y=.85,size=.85,pixelAspect=1,contactEnabled=contacts,groundFromPixel,pixelFromGround}={})=>{
|
|
362
376
|
if(![x,y,size].every(Number.isFinite)||size<=0||size>3)throw Error('Invalid paper placement');
|
|
363
377
|
const isRear=state.rearPair!==null&&state.rearPair!==undefined&&rearSample;
|
|
@@ -379,7 +393,7 @@ export function createPaperRenderer(cache,info,meta,width,height,{rear,approach,
|
|
|
379
393
|
feet=motion.feet[k].map(f=>({...f,episode:`carry/${state.comfortPose.cycle}/${f.id}`}));
|
|
380
394
|
if(state.flip)feet=feet.map(p=>({...p,x:319-p.x}));
|
|
381
395
|
}else if(contactEnabled&&isAction&&state.actionName==='walk'){
|
|
382
|
-
const p=paperActionPose('walk',state.actionProgress,actions.info);feet=walkEpisodes(actions.info.feet[p.pair][Math.round(p.blend*8)],p.pair,p.blend,state.actionProgress);
|
|
396
|
+
const p=paperActionPose('walk',state.actionProgress,actions.info,motionTables?.actionClips);feet=walkEpisodes(actions.info.feet[p.pair][Math.round(p.blend*8)],p.pair,p.blend,state.actionProgress);
|
|
383
397
|
if(state.flip)feet=feet.map(p=>({...p,x:319-p.x}));
|
|
384
398
|
}else if(contactEnabled&&rear&&state.state==='run'&&!isAction&&!isComfort){
|
|
385
399
|
const b=isBehavior?paperBehaviorPose(state,behaviors.info):null;
|
package/retrieviewer.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import {createSnappyTrickTimings} from './puppy-paper-trick-timing.mjs';
|
|
|
5
5
|
import {createCompanionLife,FETCH_RETURN_STYLES} from './puppy-companion-life.mjs';
|
|
6
6
|
import {paintCompanionObjects} from './puppy-companion-objects.mjs';
|
|
7
7
|
import {readPackedFrames} from './puppy-frame-store.mjs';
|
|
8
|
+
import {BAKED_MOTION} from './puppy-motion-tables.generated.mjs';
|
|
8
9
|
|
|
9
10
|
// Embeddable autonomous puppy. Importing or creating has no DOM, timer, stdin/stdout
|
|
10
11
|
// or listener side effects: the host owns the loop and calls step() then frame().
|
|
@@ -121,11 +122,14 @@ export async function createPet({loadAsset=defaultLoadAsset,seed,energy,pawTrans
|
|
|
121
122
|
let lease=await acquireAssets(loadAsset,artProfile),data=lease.data;
|
|
122
123
|
const release=lease.release;lease=null;
|
|
123
124
|
let {cache,info,meta}=data;const assets={...data.assets};data=null;
|
|
125
|
+
// Baked tables describe the bundled Q5 source only. External/optional artwork
|
|
126
|
+
// keeps the general metadata-driven path instead of using an unrelated bake.
|
|
127
|
+
const motionTables=loadAsset===defaultLoadAsset&&artProfile==='q5'?BAKED_MOTION:null;
|
|
124
128
|
let animal,actor,life;
|
|
125
129
|
try{
|
|
126
130
|
if(!assets.actions.info.clips?.['lie-down']||!assets.actions.info.clips?.['lie-up'])throw Error('v9 action cache lacks lie-down/lie-up clips');
|
|
127
131
|
animal=createPaperBody();
|
|
128
|
-
actor=createPaperActor(animal,info,{manualTricks:true,trickTimings:createSnappyTrickTimings(assets.actions.info),comfortTimings:createPaperComfortTimings(assets.actions.info),walkTransitions:true,scrambleSeconds:assets.comfort.info.scramble?.duration??0,fetchMotions:assets.comfort.info.version>=4?assets.comfort.info:null});
|
|
132
|
+
actor=createPaperActor(animal,info,{manualTricks:true,trickTimings:createSnappyTrickTimings(assets.actions.info),comfortTimings:createPaperComfortTimings(assets.actions.info),walkTransitions:true,scrambleSeconds:assets.comfort.info.scramble?.duration??0,fetchMotions:assets.comfort.info.version>=4?assets.comfort.info:null,motionTables});
|
|
129
133
|
life=createCompanionLife(actor,{seed,returnStyle,...energy===undefined?{}:{energy}});
|
|
130
134
|
}catch(e){animal?.dispose?.();release();throw e;}
|
|
131
135
|
let paint=null,paintKey='',time=0,acc=0,disposed=false,lastHeldFrameKey=null;
|
|
@@ -150,7 +154,7 @@ export async function createPet({loadAsset=defaultLoadAsset,seed,energy,pawTrans
|
|
|
150
154
|
if(typeof cellAspect!=='number'||!Number.isFinite(cellAspect)||cellAspect<=0)throw RangeError('cellAspect must be a positive number');
|
|
151
155
|
if(![12,24,30].includes(poseFps))throw RangeError('poseFps must be 12, 24 or 30');
|
|
152
156
|
const width=columns*2,height=rows*4,key=`${width}x${height}`;
|
|
153
|
-
if(paintKey!==key){paint=createPaperRenderer(cache,info,meta,width,height,{...assets,pawTransport});paintKey=key;}
|
|
157
|
+
if(paintKey!==key){paint=createPaperRenderer(cache,info,meta,width,height,{...assets,pawTransport,motionTables});paintKey=key;}
|
|
154
158
|
const viewportWidth=camera?.viewportWidth??columns*cellAspect,viewportHeight=camera?.viewportHeight??rows;
|
|
155
159
|
const projection=createPaperProjection({viewportWidth,viewportHeight,rect:camera?.rect??{left:0,top:0,width:viewportWidth,height:viewportHeight},width,height});
|
|
156
160
|
const state=actor.sample(time,{poseFps}),report=life.report;
|