@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.
Files changed (263) hide show
  1. package/ASSET-PROVENANCE.md +11 -0
  2. package/ASSETS-LICENSE.md +2 -1
  3. package/ATTRIBUTION.md +6 -1
  4. package/COMFORT-ART.md +95 -0
  5. package/DESKTOP-PLATFORMS.md +6 -1
  6. package/INSTALLING.md +4 -0
  7. package/PLUGIN.md +13 -10
  8. package/PREREQUISITES.md +95 -0
  9. package/PUPPY-MEMORY.md +102 -1
  10. package/README.ko.md +116 -0
  11. package/README.md +121 -59
  12. package/RELEASING.md +33 -13
  13. package/THIRD-PARTY-NOTICES.md +5 -3
  14. package/braille.mjs +35 -9
  15. package/examples/live.mjs +2 -2
  16. package/integrations/linux-overlay/overlay.py +8 -2
  17. package/integrations/macos-overlay/overlay.jxa +9 -7
  18. package/integrations/opencode/runtime.mjs +4 -4
  19. package/integrations/opencode/tui.tsx +1 -1
  20. package/integrations/windows-overlay/Overlay.cs +7 -6
  21. package/integrations/windows-overlay/desktop.mjs +2 -1
  22. package/integrations/windows-overlay/protocol.mjs +13 -7
  23. package/integrations/windows-overlay/worker.mjs +1 -1
  24. package/package.json +34 -13
  25. package/puppy-comfort-sprites.mjs +33 -0
  26. package/puppy-companion-comfort-q5.bin.gz +0 -0
  27. package/puppy-companion-comfort.json +140 -0
  28. package/puppy-companion-life.mjs +58 -18
  29. package/puppy-companion-objects.mjs +12 -0
  30. package/puppy-companion-sprites.mjs +4 -2
  31. package/puppy-frame-predictive.mjs +15 -9
  32. package/puppy-frame-store.mjs +2 -2
  33. package/puppy-paper-actions.mjs +4 -2
  34. package/puppy-paper-behaviors.mjs +1 -1
  35. package/puppy-paper-contact.mjs +4 -2
  36. package/puppy-paper-seat.mjs +4 -2
  37. package/puppy-paper-world.mjs +14 -0
  38. package/puppy-paper.mjs +79 -21
  39. package/retrieviewer-cli.mjs +8 -6
  40. package/retrieviewer-plugin.d.mts +1 -1
  41. package/retrieviewer-plugin.mjs +1 -1
  42. package/retrieviewer.d.mts +12 -4
  43. package/retrieviewer.mjs +20 -14
  44. package/locomotion-core.mjs +0 -21
  45. package/locomotion-puppy.animal +0 -0
  46. package/vendor/procedural-animals/package.json +0 -40
  47. package/vendor/procedural-animals/src/animal.js +0 -146
  48. package/vendor/procedural-animals/src/bake.js +0 -51
  49. package/vendor/procedural-animals/src/build.js +0 -81
  50. package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
  51. package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
  52. package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
  53. package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
  54. package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
  55. package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
  56. package/vendor/procedural-animals/src/core/build/seams.js +0 -183
  57. package/vendor/procedural-animals/src/core/build/warp.js +0 -112
  58. package/vendor/procedural-animals/src/core/build/weights.js +0 -393
  59. package/vendor/procedural-animals/src/core/math/vec.js +0 -81
  60. package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
  61. package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
  62. package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
  63. package/vendor/procedural-animals/src/core/motion/common.js +0 -158
  64. package/vendor/procedural-animals/src/core/motion/index.js +0 -22
  65. package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
  66. package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
  67. package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
  68. package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
  69. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
  70. package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
  71. package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
  72. package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
  73. package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
  74. package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
  75. package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
  76. package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
  77. package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
  78. package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
  79. package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
  80. package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
  81. package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
  82. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
  83. package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
  84. package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
  85. package/vendor/procedural-animals/src/index.d.ts +0 -98
  86. package/vendor/procedural-animals/src/index.js +0 -29
  87. package/vendor/procedural-animals/src/registry.js +0 -48
  88. package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
  89. package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
  90. package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
  91. package/vendor/procedural-animals/src/species/bear/index.js +0 -139
  92. package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
  93. package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
  94. package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
  95. package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
  96. package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
  97. package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
  98. package/vendor/procedural-animals/src/species/boar/index.js +0 -110
  99. package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
  100. package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
  101. package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
  102. package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
  103. package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
  104. package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
  105. package/vendor/procedural-animals/src/species/cat/index.js +0 -211
  106. package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
  107. package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
  108. package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
  109. package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
  110. package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
  111. package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
  112. package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
  113. package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
  114. package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
  115. package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
  116. package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
  117. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
  118. package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
  119. package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
  120. package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
  121. package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
  122. package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
  123. package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
  124. package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
  125. package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
  126. package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
  127. package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
  128. package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
  129. package/vendor/procedural-animals/src/species/cow/index.js +0 -118
  130. package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
  131. package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
  132. package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
  133. package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
  134. package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
  135. package/vendor/procedural-animals/src/species/crow/index.js +0 -70
  136. package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
  137. package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
  138. package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
  139. package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
  140. package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
  141. package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
  142. package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
  143. package/vendor/procedural-animals/src/species/deer/index.js +0 -106
  144. package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
  145. package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
  146. package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
  147. package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
  148. package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
  149. package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
  150. package/vendor/procedural-animals/src/species/dog/index.js +0 -144
  151. package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
  152. package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
  153. package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
  154. package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
  155. package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
  156. package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
  157. package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
  158. package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
  159. package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
  160. package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
  161. package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
  162. package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
  163. package/vendor/procedural-animals/src/species/fish/index.js +0 -88
  164. package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
  165. package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
  166. package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
  167. package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
  168. package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
  169. package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
  170. package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
  171. package/vendor/procedural-animals/src/species/fox/index.js +0 -120
  172. package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
  173. package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
  174. package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
  175. package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
  176. package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
  177. package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
  178. package/vendor/procedural-animals/src/species/frog/index.js +0 -97
  179. package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
  180. package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
  181. package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
  182. package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
  183. package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
  184. package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
  185. package/vendor/procedural-animals/src/species/goat/index.js +0 -149
  186. package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
  187. package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
  188. package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
  189. package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
  190. package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
  191. package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
  192. package/vendor/procedural-animals/src/species/horse/index.js +0 -80
  193. package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
  194. package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
  195. package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
  196. package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
  197. package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
  198. package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
  199. package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
  200. package/vendor/procedural-animals/src/species/lion/index.js +0 -111
  201. package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
  202. package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
  203. package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
  204. package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
  205. package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
  206. package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
  207. package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
  208. package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
  209. package/vendor/procedural-animals/src/species/pig/index.js +0 -161
  210. package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
  211. package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
  212. package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
  213. package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
  214. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
  215. package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
  216. package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
  217. package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
  218. package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
  219. package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
  220. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
  221. package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
  222. package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
  223. package/vendor/procedural-animals/src/species/rat/index.js +0 -111
  224. package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
  225. package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
  226. package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
  227. package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
  228. package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
  229. package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
  230. package/vendor/procedural-animals/src/species/shark/index.js +0 -104
  231. package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
  232. package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
  233. package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
  234. package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
  235. package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
  236. package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
  237. package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
  238. package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
  239. package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
  240. package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
  241. package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
  242. package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
  243. package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
  244. package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
  245. package/vendor/procedural-animals/src/species/snake/index.js +0 -73
  246. package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
  247. package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
  248. package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
  249. package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
  250. package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
  251. package/vendor/procedural-animals/src/species/spider/index.js +0 -78
  252. package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
  253. package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
  254. package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
  255. package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
  256. package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
  257. package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
  258. package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
  259. package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
  260. package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
  261. package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
  262. package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
  263. package/vendor/procedural-animals/src/worker.js +0 -29
@@ -1,285 +0,0 @@
1
- // The rabbit's coat: dense soft agouti fur (banded hair tips), countershading to a white belly, the
2
- // rufous nape patch, pale eye rings, dark-rimmed ears with thinly furred pink insides, the scut
3
- // (dark on top, white underneath), furred feet; domestic colours as seeded variants (fawn, black,
4
- // white / REW albino, Dutch pied pattern grown as a signed distance on the surface).
5
- // Works in the reference space of rig.js; colours sampled from the reference photos.
6
- import { HEAD_O } from './rig.js';
7
- import { neckS } from './regions.js';
8
- import { SDFModel } from '../../core/sdf/sdf.js';
9
- import { norm, sub, dot, cross, len, add, mul, smoothstep, clamp, mix, fbm3 } from '../../core/math/vec.js';
10
- import { srgb, mix3, MAT } from '../../core/build/coatKit.js';
11
-
12
- // palette per colour variant (sRGB hex from reference photos)
13
- const PALETTES = {
14
- agouti: {
15
- back: 0x7d6c56, flank: 0x8d7a62, low: 0xa4907a, nape: 0x9c6a42, face: 0x937c5e, cheek: 0x9c8a6c,
16
- eyeRing: 0xcfc2a6, earOut: 0x8a7a64, earRim: 0x3b3024, earIn: 0xc9a193, chest: 0x9a7e5c,
17
- belly: 0xe8e2d6, tailTop: 0x3e342a, tailUnder: 0xf4f2ee, feet: 0xa8977e, nose: 0x8e6e62, claw: 0x6a5c50,
18
- agouti: 1.0, undercoat: 0.6,
19
- },
20
- fawn: {
21
- back: 0xc08a4c, flank: 0xc8955a, low: 0xd6a86c, nape: 0xd49a58, face: 0xcc975c, cheek: 0xd2a066,
22
- eyeRing: 0xe8d0a4, earOut: 0xbc8850, earRim: 0x8a5e32, earIn: 0xd8a898, chest: 0xd4a46a,
23
- belly: 0xf0e2c8, tailTop: 0xb07a40, tailUnder: 0xf4ecdc, feet: 0xe0c090, nose: 0xc89486, claw: 0xd8ccbc,
24
- agouti: 0.15, undercoat: 0.35,
25
- },
26
- black: {
27
- back: 0x2c2826, flank: 0x302b28, low: 0x39332f, nape: 0x2f2926, face: 0x302b28, cheek: 0x332d2a,
28
- eyeRing: 0x39332f, earOut: 0x2c2826, earRim: 0x1c1918, earIn: 0x7a6260, chest: 0x302b28,
29
- belly: 0x3e3733, tailTop: 0x1a1817, tailUnder: 0x2c2724, feet: 0x2a2522, nose: 0x3a2e2c, claw: 0x2a2624,
30
- agouti: 0.0, undercoat: 0.2,
31
- },
32
- white: {
33
- back: 0xece8e0, flank: 0xeeeae2, low: 0xf0ece4, nape: 0xece8e0, face: 0xeeeae2, cheek: 0xf0ece6,
34
- eyeRing: 0xf2eee8, earOut: 0xe8e2da, earRim: 0xe4dcd2, earIn: 0xe8b8b0, chest: 0xf0ece4,
35
- belly: 0xf4f2ee, tailTop: 0xeeeae2, tailUnder: 0xf6f4f0, feet: 0xf0ece4, nose: 0xd8a0a0, claw: 0xece4da,
36
- agouti: 0.0, undercoat: 0.1,
37
- },
38
- };
39
- // Dutch: the coloured parts (cheeks, ears, rear half) take the chosen base; white elsewhere
40
- const DUTCH_WHITE = 0xf2f0ea;
41
-
42
- function coatColours(p) {
43
- const base = PALETTES[p.colour || 'agouti'] || PALETTES.agouti;
44
- const k = p.coatWarmth || 0, l = p.coatLightness || 0;
45
- const tweak = (h) => { const c = srgb(h); return [c[0] * (1 + 0.16 * k + l), c[1] * (1 + 0.04 * k + l), c[2] * (1 - 0.16 * k + l)]; };
46
- const C = {};
47
- for (const [key, v] of Object.entries(base)) C[key] = typeof v === 'number' && key !== 'agouti' && key !== 'undercoat' ? (['belly', 'tailUnder', 'earIn', 'nose', 'claw'].includes(key) ? srgb(v) : tweak(v)) : v;
48
- return C;
49
- }
50
-
51
- export function rabbitCoat(ctx) {
52
- const { model, rig, pos, nrm, regionOf: partOf, weights, nV, params } = ctx;
53
- const { BONES, AXIAL } = rig;
54
- const COL = coatColours(params);
55
- const { dominant, axialS, skinIndex, skinWeight, limbMember } = weights;
56
- const AX = weights.axialLengths;
57
- const P = (v) => [pos[v * 3], pos[v * 3 + 1], pos[v * 3 + 2]];
58
- const N = (v) => [nrm[v * 3], nrm[v * 3 + 1], nrm[v * 3 + 2]];
59
- const sOcc = AX[1], sNeckBase = AX[3], sTailBase = AX[8];
60
- const isLimb = BONES.map((b) => /^(scapula|humerus|radius|metacarpus|fpaw|femur|tibia|metatarsus|hpaw)/.test(b.name));
61
- const isFoot = BONES.map((b) => /^(fpaw|hpaw|metacarpus)/.test(b.name));
62
- const isHindFoot = BONES.map((b) => /^(hpaw|metatarsus)/.test(b.name));
63
- const eyePrims = model.prims.filter((p) => p.tag === 'eyesocket');
64
- const nosePrim = model.prims.find((p) => p.tag === 'nose');
65
- const cleftPrim = model.prims.find((p) => p.tag === 'lipcleft');
66
- const earPrims = model.prims.filter((p) => p.tag === 'ear');
67
- const jawPrims = model.forPart('jaw');
68
- const headPrims = model.forPart('body').filter((p) => (p.bone === 'head' || p.bone === 'snout') && !p.carve);
69
- const dutch = !!params.dutch;
70
- const albino = params.colour === 'white';
71
-
72
- const region = new Uint8Array(nV); // 0 torso, 1 neck, 2 head, 4 tail, 5 ear, 6 jaw, 7 snout
73
- const legness = new Float32Array(nV);
74
- const legBone = new Int16Array(nV).fill(-1);
75
- for (let v = 0; v < nV; v++) {
76
- const bn = BONES[dominant[v]].name;
77
- const p = P(v);
78
- let lb = -1, lw = 0;
79
- for (let k = 0; k < 4; k++) {
80
- const b = skinIndex[v * 4 + k], w = skinWeight[v * 4 + k];
81
- if (isLimb[b] && w > lw) { lw = w; lb = b; }
82
- }
83
- legBone[v] = lb;
84
- legness[v] = lb >= 0 ? smoothstep(0.15, 0.85, limbMember[v]) : 0;
85
- if (partOf[v] === 2) region[v] = 6;
86
- else if (bn.startsWith('ear')) region[v] = 5;
87
- else if (bn === 'snout') region[v] = 7;
88
- else if (axialS[v] > sTailBase + 0.004 && bn.startsWith('tail')) region[v] = 4;
89
- else if (axialS[v] < sOcc + 0.004 || (partOf[v] === 1 && neckS(p[0], p[1], p[2]) > 0.01)) region[v] = 2;
90
- else if (axialS[v] < sNeckBase) region[v] = 1;
91
- else region[v] = 0;
92
- if (region[v] === 2 || region[v] >= 4) legness[v] = 0;
93
- }
94
-
95
- // Dutch pattern: signed distance (m, < 0 = white) of the white areas: blaze and muzzle, a collar
96
- // and the whole forequarters (the "saddle" line behind the shoulders), and the hind feet ("stops")
97
- const dutchSDF = (p, r, v) => {
98
- const h = sub(p, HEAD_O);
99
- if (r === 5 || r === 4) return 1; // ears and scut stay coloured
100
- if (r === 2 || r === 6 || r === 7) {
101
- // blaze: a wedge between the eyes widening to the muzzle; muzzle, lips, chin and throat white
102
- const blaze = Math.abs(h[0]) - (0.003 + 0.3 * Math.max(0, h[2] + 0.004));
103
- return Math.min(blaze, 0.024 - h[2], h[1] + 0.027);
104
- }
105
- // saddle line behind the shoulders, slanting back low on the body
106
- let d = (-0.02 - 0.25 * (0.12 - p[1]) + 0.003 * Math.sin(p[0] * 70)) - p[2];
107
- // hind feet: white "stops" from the toes to about mid-foot
108
- if (legBone[v] >= 0 && isHindFoot[legBone[v]]) d = Math.min(d, -0.072 - p[2]);
109
- return d;
110
- };
111
-
112
- const comb = new Float32Array(nV * 3);
113
- const tint = new Float32Array(nV * 4);
114
- const furLen = new Float32Array(nV);
115
- const markSDF = new Float32Array(nV).fill(1);
116
- const pattern = new Float32Array(nV).fill(1);
117
- const patternColor = new Float32Array(nV * 4);
118
- const surf = new Float32Array(nV * 4);
119
- const white = srgb(DUTCH_WHITE);
120
-
121
- for (let v = 0; v < nV; v++) {
122
- const p = P(v), n = N(v), r = region[v];
123
- const h = sub(p, HEAD_O);
124
- const bone = BONES[dominant[v]];
125
- const L = legness[v];
126
- let col, fl, mat = MAT.FUR, mark = 1, ag = COL.agouti, uc = COL.undercoat;
127
-
128
- // ---- comb
129
- let d;
130
- if (r === 5) d = norm(sub(bone.tail, bone.head));
131
- else if (r === 2 || r === 6 || r === 7) d = norm(add(norm(sub(h, [0, -0.018, 0.05])), [0, -0.1, -0.5]));
132
- else if (r === 4) d = norm(add(norm(sub(bone.tail, bone.head)), [0, 0.3, -0.3]));
133
- else {
134
- const seg = weights.segT[v * 2] | 0;
135
- const a = AXIAL.points[seg], b = AXIAL.points[Math.min(seg + 1, AXIAL.points.length - 1)];
136
- d = norm(add(norm(sub(b, a)), [0, -0.45 * Math.abs(n[0]), 0]));
137
- if (L > 0 && legBone[v] >= 0) {
138
- const lbn = BONES[legBone[v]];
139
- let dl = norm(sub(lbn.tail, lbn.head));
140
- if (/fpaw|hpaw|metatarsus/.test(lbn.name)) dl = norm(add(dl, [0, 0, 0.5]));
141
- else dl = norm(add(dl, [0, -0.3, -0.2]));
142
- d = norm(add(mul(d, 1 - L), mul(dl, L)));
143
- }
144
- }
145
- let t = sub(d, mul(n, dot(d, n)));
146
- if (len(t) < 1e-4) t = cross(n, [1, 0, 0]);
147
- t = norm(t);
148
- comb[v * 3] = t[0]; comb[v * 3 + 1] = t[1]; comb[v * 3 + 2] = t[2];
149
-
150
- // ---- colour, fur length, marks
151
- if (r === 0 || r === 1) {
152
- const up = clamp(n[1], -1, 1);
153
- col = mix3(COL.low, COL.flank, smoothstep(-0.3, 0.3, up));
154
- col = mix3(col, COL.back, smoothstep(0.3, 0.9, up));
155
- // rufous nape patch behind the ears
156
- col = mix3(col, COL.nape, smoothstep(0.2, 0.7, up) * (r === 1 ? 1 : smoothstep(0.06, 0.085, p[2])) * 0.8);
157
- // chest: buff, belly: white (countershading blended by normal and height)
158
- const ventral = smoothstep(-0.1, -0.6, n[1]) * smoothstep(0.14, 0.07, p[1]);
159
- const chest = smoothstep(0.03, 0.08, p[2]) * smoothstep(0.1, 0.5, n[2]) * smoothstep(0.15, 0.08, p[1]);
160
- col = mix3(col, COL.chest, chest * 0.8);
161
- col = mix3(col, COL.belly, Math.max(ventral, smoothstep(0.35, 0.8, -n[1])));
162
- fl = mix(0.0105, 0.012, smoothstep(0.3, -0.6, n[1]));
163
- fl = Math.max(fl, 0.012 * smoothstep(0.6, 0.95, n[1])); // dense back
164
- // rump fur a touch longer (the rounded loaf outline)
165
- if (p[2] < -0.1) fl += 0.002 * smoothstep(-0.1, -0.16, p[2]);
166
- ag *= 1 - smoothstep(0.2, 0.7, -n[1]);
167
- if (L > 0) {
168
- let lc = mix3(COL.flank, COL.belly, smoothstep(0.0, -0.8, n[0] * Math.sign(p[0] || 1)) * 0.7);
169
- const lb = legBone[v] >= 0 ? BONES[legBone[v]].name : '';
170
- let lf = mix(0.005, 0.0105, smoothstep(0.02, 0.1, p[1]));
171
- if (/fpaw|hpaw|metacarpus|metatarsus/.test(lb)) { lc = mix3(mix3(COL.feet, COL.flank, 0.35), COL.belly, smoothstep(0.0, -0.7, n[1]) * 0.4); lf = 0.006; }
172
- else if (/radius/.test(lb)) { lc = mix3(COL.feet, COL.flank, 0.5); lf = 0.005; }
173
- // the big haunch keeps the body colour on its outside
174
- if (/femur/.test(lb)) { lc = mix3(col, lc, smoothstep(0.08, 0.03, p[1])); lf = mix(fl, lf, 0.4); }
175
- col = mix3(col, lc, L);
176
- fl = mix(fl, lf, L);
177
- ag *= 1 - 0.6 * L * (/fpaw|hpaw|metacarpus|metatarsus|radius/.test(lb) ? 1 : 0);
178
- }
179
- } else if (r === 4) {
180
- // the scut: dark on top (the side facing out at rest), bright white underneath
181
- const bb = BONES[dominant[v]];
182
- const ax = norm(sub(bb.tail, bb.head));
183
- // "top" of the tail = its dorsal side (toward the back when curled down against the rump)
184
- const dorsal = norm(cross([1, 0, 0], ax));
185
- const top = dot(n, dorsal);
186
- col = mix3(COL.tailUnder, COL.tailTop, smoothstep(-0.1, 0.45, -top));
187
- fl = 0.016;
188
- ag *= 0.3;
189
- } else if (r === 5) {
190
- // ears: short fur outside with a dark rim, sparse hair on the pink inner skin
191
- const side = p[0] >= 0 ? 0 : 1;
192
- const ep = earPrims[side];
193
- const face = [ep.P[9], ep.P[10], ep.P[11]];
194
- const upE = [ep.P[6], ep.P[7], ep.P[8]], latE = [ep.P[3], ep.P[4], ep.P[5]];
195
- const c = [ep.P[0], ep.P[1], ep.P[2]];
196
- const q = sub(p, c);
197
- const along = dot(q, upE) / ep.P[13], across = dot(q, latE) / ep.P[12];
198
- const rim = 1 - Math.hypot(along, across); // 0 at the edge of the pinna
199
- const front = dot(n, face) * Math.sign(dot(face, [p[0] >= 0 ? 1 : -1, 0, 0]) || 1);
200
- const inner = smoothstep(0.1, 0.5, dot(n, face)) * smoothstep(0.02, 0.12, rim);
201
- col = mix3(COL.earOut, COL.earIn, inner);
202
- fl = mix(0.0022, 0.0009, inner);
203
- if (inner > 0.6) mat = albino || params.colour === 'black' ? MAT.FUR : MAT.FUR;
204
- // dark rim along the outer edge and the tip (wild / agouti)
205
- // a thin dark rim along the upper edge and around the tip only (not at the root)
206
- if (along > 0.1) mark = Math.min(mark, (rim - 0.035) * 0.03 + 0.003 * (1 - smoothstep(0.1, 0.6, along)));
207
- if (params.colour !== 'agouti') mark = 1;
208
- ag *= 0.5 * (1 - inner);
209
- void front;
210
- } else {
211
- // head, snout and jaw
212
- col = COL.face;
213
- const g3 = (cc, rr) => Math.exp(-(((Math.abs(h[0]) - cc[0]) / rr[0]) ** 2 + ((h[1] - cc[1]) / rr[1]) ** 2 + ((h[2] - cc[2]) / rr[2]) ** 2));
214
- col = mix3(col, COL.cheek, g3([0.017, -0.02, -0.005], [0.01, 0.012, 0.02]));
215
- // pale eye ring (the "spectacles") and pale lips / chin
216
- let ring = 0;
217
- for (const e of eyePrims) {
218
- const de = SDFModel.dist(e, p[0], p[1], p[2]);
219
- ring = Math.max(ring, smoothstep(0.0055, 0.0015, Math.abs(de)));
220
- }
221
- col = mix3(col, COL.eyeRing, ring * 0.6);
222
- const lips = g3([0.006, -0.03, 0.036], [0.009, 0.006, 0.014]);
223
- const chinW = r === 6 ? 0.9 : smoothstep(-0.028, -0.036, h[1]) * smoothstep(-0.2, -0.7, n[1]);
224
- col = mix3(col, COL.belly, clamp(Math.max(lips * 0.7, chinW), 0, 1));
225
- // nape colour at the back of the head
226
- col = mix3(col, COL.nape, smoothstep(-0.02, -0.04, h[2]) * smoothstep(0.0, 0.6, n[1]) * 0.6);
227
- fl = mix(0.0045, 0.0028, smoothstep(0.0, 0.035, h[2]));
228
- if (Math.abs(h[0]) > 0.016 && h[1] < -0.005) fl = Math.max(fl, 0.0055); // cheek fur
229
- ag *= 0.7;
230
- // eye rims: dark bare lid margin
231
- for (const e of eyePrims) {
232
- const de = SDFModel.dist(e, p[0], p[1], p[2]);
233
- if (Math.abs(de) < 0.0022) mark = Math.min(mark, Math.abs(de) - 0.0009);
234
- if (Math.abs(de) < 0.0009) { mat = MAT.DARK_SKIN; fl = 0; }
235
- else if (Math.abs(de) < 0.0025) fl = Math.min(fl, 0.001);
236
- }
237
- // nose leather (small, Y-shaped with the lip cleft) and the cleft itself
238
- if (nosePrim && SDFModel.dist(nosePrim, p[0], p[1], p[2]) < 0.0009 && h[2] > 0.0355 && h[1] > -0.024) { mat = MAT.NOSE; col = COL.nose; fl = 0; }
239
- if (cleftPrim) {
240
- const dc = SDFModel.dist(cleftPrim, p[0], p[1], p[2]);
241
- if (dc < 0.0012) { mark = Math.min(mark, dc - 0.0008); fl = Math.min(fl, 0.0008); }
242
- }
243
- // whisker pads: short dense fur
244
- if (r === 7) fl = Math.min(fl, 0.0032);
245
- // lips: head vertices touching the jaw surface, jaw vertices touching the head
246
- if (partOf[v] !== 2) {
247
- const dj = SDFModel.evalList(jawPrims, p[0], p[1], p[2]);
248
- if (dj < 0.0006) { mat = MAT.MOUTH; col = [0.3, 0.12, 0.12]; fl = 0; }
249
- } else {
250
- const dh = SDFModel.evalList(headPrims, p[0], p[1], p[2]);
251
- if (dh < 0.0) { mat = MAT.MOUTH; col = [0.3, 0.12, 0.12]; fl = 0; }
252
- }
253
- }
254
-
255
- // ---- Dutch white areas (pattern SDF, crisp but hair-ragged edges)
256
- if (dutch) {
257
- pattern[v] = dutchSDF(p, r, v);
258
- }
259
-
260
- // low-frequency colour variation
261
- const cv = fbm3(p[0] * 40, p[1] * 40, p[2] * 40, 3) - 0.5;
262
- col = [col[0] * (1 + 0.14 * cv), col[1] * (1 + 0.12 * cv), col[2] * (1 + 0.09 * cv)];
263
-
264
- tint[v * 4] = col[0]; tint[v * 4 + 1] = col[1]; tint[v * 4 + 2] = col[2]; tint[v * 4 + 3] = mat;
265
- furLen[v] = mat === MAT.FUR ? fl : 0;
266
- markSDF[v] = mark;
267
- patternColor[v * 4] = white[0]; patternColor[v * 4 + 1] = white[1]; patternColor[v * 4 + 2] = white[2]; patternColor[v * 4 + 3] = dutch ? 1 : 0;
268
- surf[v * 4] = 0; surf[v * 4 + 1] = 0; surf[v * 4 + 2] = clamp(ag, 0, 1); surf[v * 4 + 3] = uc;
269
- }
270
-
271
- // smooth fur length so shells do not step
272
- const nb = weights.neighbors;
273
- const tmp = new Float32Array(nV);
274
- for (let it = 0; it < 2; it++) {
275
- for (let v = 0; v < nV; v++) {
276
- const ns = nb[v];
277
- if (!ns.length || tint[v * 4 + 3] > 0) { tmp[v] = furLen[v]; continue; }
278
- let a = 0;
279
- for (const q of ns) a += furLen[q];
280
- tmp[v] = 0.5 * furLen[v] + (0.5 * a) / ns.length;
281
- }
282
- furLen.set(tmp);
283
- }
284
- return { comb, tint, pattern, mark: markSDF, furLen, patternColor, surf, region };
285
- }
@@ -1,85 +0,0 @@
1
- // European rabbit (Oryctolagus cuniculus): the wild agouti rabbit plus the common domestic colours.
2
- // The body plan proves the hopping path of the quadruped engine: long hind legs, feet flat at rest
3
- // and on the toes in motion, half-bound and bound gaits with the hind feet landing together, a
4
- // crouched resting stance, and rabbit behaviours (hop, nose twitch, ear swivels, grooming,
5
- // periscope, thumping, binky, zig-zag escape, grazing, boxing).
6
- import { rabbitRig, HEAD_O } from './rig.js';
7
- import { sculptRabbit, EYE } from './sculpt.js';
8
- import { rabbitRegions } from './regions.js';
9
- import { rabbitCoat } from './coat.js';
10
- import { motion } from './motion.js';
11
-
12
- // Seeded individual.
13
- // variant: 'wild' (default: agouti, the European rabbit), 'domestic' (random domestic colour),
14
- // 'agouti-domestic', 'fawn', 'black', 'white' (REW albino), 'dutch' (pied), 'lop'
15
- // age: 'adult' | 'juvenile' (a kit ~4-6 weeks: round head, short ears, big eyes and feet)
16
- function variation(R, o) {
17
- const sex = o.sex || (R() < 0.5 ? 'male' : 'female');
18
- const age = o.age || 'adult';
19
- const juv = age === 'juvenile';
20
- const g = () => (R() + R() + R() - 1.5) / 1.5; // ~[-1, 1], peaked
21
- const u = () => 2 * R() - 1; // uniform [-1, 1]
22
- let variant = o.variant || 'wild';
23
- if (variant === 'domestic') variant = ['agouti-domestic', 'fawn', 'black', 'white', 'dutch', 'lop'][Math.floor(R() * 6)];
24
- const domestic = variant !== 'wild';
25
- const lop = variant === 'lop';
26
- // colour: wild and agouti-domestic are agouti; lops come in any colour
27
- let colour = { wild: 'agouti', 'agouti-domestic': 'agouti', fawn: 'fawn', black: 'black', white: 'white', dutch: R() < 0.6 ? 'black' : 'agouti', lop: ['agouti', 'fawn', 'black', 'white'][Math.floor(R() * 4)] }[variant] || 'agouti';
28
- // size: wild 1.5-2.2 kg (length ~ mass^1/3); domestic breeds 1-3.5 kg; kits ~0.2-0.4 kg
29
- let size = (domestic ? 1.06 + 0.08 * g() : 1 + 0.07 * u()) * (sex === 'male' ? 1.01 : 0.99);
30
- if (juv) size *= 0.58;
31
- const earLen = (domestic ? 0.92 : 1) * (1 + 0.07 * g()) * (juv ? 0.78 : 1);
32
- return {
33
- sex, age, size, variant, colour, domestic, lop,
34
- dutch: variant === 'dutch',
35
- earLen,
36
- earWidth: (lop ? 1.25 : 1) * (1 + 0.05 * g()),
37
- headWidth: (domestic ? 1.06 : 1) * (sex === 'male' ? 1.03 : 1) * (juv ? 1.06 : 1),
38
- minThick: 0.0011,
39
- warps: [
40
- { type: 'legs', k: 1 + 0.04 * g() - (juv ? 0.04 : 0), top: 0.08 },
41
- { type: 'length', k: 1 + 0.03 * g() - (domestic ? 0.03 : 0) - (juv ? 0.06 : 0), z0: -0.12, z1: 0.07 },
42
- { type: 'girth', k: 1 + 0.06 * g() + (domestic ? 0.05 : 0), cy: 0.12, z0: -0.15, z1: 0.1 },
43
- { type: 'scaleAbout', c: HEAD_O, k: (sex === 'male' ? 1.02 : 0.99) * (1 + 0.02 * g()) * (juv ? 1.2 : 1) * (domestic ? 1.03 : 1), r0: 0.035, r1: 0.075 },
44
- ],
45
- coatWarmth: 1.1 * u(),
46
- coatLightness: 0.12 * u(),
47
- coatSeed: Math.floor(R() * 1e6),
48
- };
49
- }
50
-
51
- export default {
52
- id: 'rabbit',
53
- name: 'European rabbit',
54
- latin: 'Oryctolagus cuniculus',
55
- group: 'paws',
56
- plan: 'quadruped',
57
- covering: 'fur',
58
- variation,
59
- rig: (params) => rabbitRig(params),
60
- sculpt: (m, rig, params) => sculptRabbit(m, rig, params),
61
- regions: rabbitRegions,
62
- coat: rabbitCoat,
63
- eyeSpecs: (params) => [1, -1].map((side) => ({ side, spec: EYE, headOrigin: HEAD_O, bone: 'head', look: params.colour === 'white' ? EYE_ALBINO : EYE_LOOK })),
64
- motion,
65
- render: { markColor: [0.018, 0.014, 0.011], strandDensity: 1500, clumpDensity: 1.2, shellScale: 1, finWidth: 0.45 },
66
- };
67
-
68
- // Round pupil in a dark brown iris that fills the whole opening (no sclera shows).
69
- export const EYE_LOOK = {
70
- pupil: 'round',
71
- lids: 'mammal',
72
- iris: { inner: [0.02, 0.011, 0.006], mid: [0.045, 0.024, 0.012], hi: [0.1, 0.06, 0.03], outer: [0.012, 0.007, 0.004] },
73
- sclera: { color: [0.03, 0.02, 0.015], visible: false },
74
- lidColor: [0.05, 0.035, 0.028],
75
- pupilSize: [0.45, 0.62],
76
- };
77
- // REW albino: pale pink iris, red pupil (the fundus shows through)
78
- export const EYE_ALBINO = {
79
- pupil: 'round',
80
- lids: 'mammal',
81
- iris: { inner: [0.55, 0.12, 0.14], mid: [0.75, 0.42, 0.44], hi: [0.9, 0.6, 0.6], outer: [0.6, 0.3, 0.32] },
82
- sclera: { color: [0.6, 0.35, 0.35], visible: false },
83
- lidColor: [0.75, 0.5, 0.48],
84
- pupilSize: [0.35, 0.5],
85
- };
@@ -1,85 +0,0 @@
1
- // Rabbit motion data for the quadruped engine (schema: src/core/motion/quadruped.js).
2
- // Numbers are for the reference individual (params.size = 1, wild adult ~1.8 kg, hip height when
3
- // hopping ~0.15 m); the engine scales them by dynamic similarity for kits and big domestic breeds.
4
- //
5
- // Gaits (Hall et al. 2022, Kraatz et al. 2021, Heglund et al. 1974): rabbits
6
- // almost never walk. Grazing "shuffle" (hop-step: forefeet one after the other, both hind feet
7
- // slide forward together), half-bound (forefeet land one after the other, the hind feet land
8
- // TOGETHER beside / ahead of the forefeet) and the bound-like escape half-bound with a long
9
- // extended suspension. Offsets [FL, FR, HL, HR] relative to hind touchdown; HL = HR (feet together).
10
- import { hooks } from './behaviour.js';
11
-
12
- const G = (name, v, f, D, off, o) => ({ name, v, f, D, off, ...o });
13
-
14
- export const motion = {
15
- // engine constants scale with the leg length relative to the cheetah's (0.234 m / 0.774 m)
16
- unit: 0.3,
17
- maxSpeed: 8,
18
- // (a hopper: its bound already folds the hind legs deep, and its hops carry their own bounce: the
19
- // engine's moving crouch, stride roll and variation jittered the hocks and wrists, and sitting back
20
- // on its haunches to brake pressed its long flat hind feet into the ground)
21
- moveCrouch: 0, stride: { bob: 1, bobSpring: true, roll: 0, vary: 0, brake: 0, gallop: 0 },
22
- accel: [9, 16],
23
- decel: 14,
24
- turnRate: 5.5,
25
- latAccelMax: 22,
26
- gears: { shuffle: 0.25, halfbound: 1.2, bound: 3.5 },
27
- gallopBlend: [1.2, 4],
28
- // the back flexes and extends in every hop, not only at a gallop
29
- flexBlend: [0.3, 1.5],
30
- hooks,
31
- gaits: [
32
- G('shuffle', 0.0, 1.3, 0.74, [0.44, 0.6, 0.0, 0.0], { liftF: 0.018, liftH: 0.02, bobF: 0.004, bobH: 0.01, flex: 0.04, lat: 0, fold: -0.2, heel: 10, tail: 0.1, drop: 0 }),
33
- G('shuffle', 0.35, 1.7, 0.62, [0.46, 0.6, 0.0, 0.0], { liftF: 0.024, liftH: 0.028, bobF: 0.006, bobH: 0.016, flex: 0.06, lat: 0, fold: -0.2, heel: 14, tail: 0.2, drop: 0 }),
34
- G('halfbound', 0.7, 2.2, 0.34, [0.5, 0.62, 0.0, 0.0], { liftF: 0.035, liftH: 0.045, bobF: 0.012, bobH: 0.02, flex: 0.1, lat: 0, fold: -0.2, heel: 18, tail: 0.4, drop: -0.012 }),
35
- G('halfbound', 1.8, 2.8, 0.26, [0.46, 0.58, 0.0, 0.0], { liftF: 0.045, liftH: 0.055, bobF: 0.016, bobH: 0.024, flex: 0.13, lat: 0, fold: -0.2, heel: 22, tail: 0.6, drop: -0.02 }),
36
- G('bound', 3.2, 3.4, 0.2, [0.44, 0.54, 0.0, 0.0], { liftF: 0.055, liftH: 0.06, bobF: 0.018, bobH: 0.026, flex: 0.17, lat: 0, fold: -0.2, heel: 25, tail: 0.85, drop: -0.022 }),
37
- G('bound', 6.5, 4.0, 0.16, [0.42, 0.52, 0.0, 0.0], { liftF: 0.06, liftH: 0.065, bobF: 0.02, bobH: 0.028, flex: 0.2, lat: 0, fold: -0.2, heel: 25, tail: 1, drop: -0.024 }),
38
- G('bound', 10, 4.4, 0.14, [0.42, 0.52, 0.0, 0.0], { liftF: 0.065, liftH: 0.07, bobF: 0.02, bobH: 0.03, flex: 0.22, lat: 0, fold: -0.2, heel: 25, tail: 1, drop: -0.026 }),
39
- ],
40
- feet: {
41
- // short forelegs: land close in front of the shoulder and lift early (limits / leg length)
42
- front: { type: 'digitigrade', curl: 50, contact: 0.5, flex: 4, lead: 0.15, liftBehind: 0.8, retract: 0.8, elbowDown: 0.4 },
43
- // flat on the ground at rest (bind), on the toes in motion (the pantograph lifts the heel)
44
- hind: { type: 'digitigrade', curl: 40, contact: 0.55, retract: 0.8, liftBehind: 0.25, plantRest: true, restTilt: 6 },
45
- },
46
- stance: { width: 1, gallopWidth: 0.85, sprawl: 0, crouch: 0, scuff: [6, 12, 0] },
47
- body: {
48
- // (sections of the half-extended bind sculpt: brisket bottom ~47 mm, belly ~35 mm, rump ~60 mm)
49
- chest: { y: 0.105, hh: 0.068, hw: 0.053 },
50
- pelvis: { y: 0.11, hh: 0.05, hw: 0.075 },
51
- mid: { y: 0.095, hh: 0.06, hw: 0.07 },
52
- back: 0.045,
53
- },
54
- head: {
55
- // [speed, raise (m), reach (m), pitch (rad, + = nose down)]
56
- carriage: [[0, 0, 0, 0], [0.7, -0.008, 0.006, 0.08], [3, -0.015, 0.012, 0.12], [8, -0.02, 0.018, 0.15]],
57
- stab: [[0, 0], [0.5, 0.15], [1.5, 0.2], [4, 0.25], [8, 0.3]],
58
- // a rabbit sees almost all round: it turns its head little (the skin of the short neck is
59
- // stretched by every degree the skull turns on the atlas)
60
- neckBend: 40, neckPivot: 0.5, yaw: 0.55, pitchUp: 0.4, pitchDown: 0.5,
61
- },
62
- tail: {
63
- // the scut is pressed down against the rump at rest and flipped up at speed (white flag)
64
- carriage: [
65
- [0.0, [-12, -24, -36]],
66
- [0.7, [-10, -18, -26]],
67
- [2.5, [-8, 12, 35]],
68
- [5, [-2, 28, 60]],
69
- ],
70
- stiffness: 2.2, sway: 0, flick: 0.4, wag: 0, swish: 0, curl: 0, balance: 0,
71
- radius: [0.014, 0.012],
72
- },
73
- ears: { mobility: 0.7, speedFlatten: 0.9, flattenSpeeds: [1.5, 7], twitch: 1.5, prick: 0.6 },
74
- breath: { rate: 0.8, amp: 0.02, pant: false, heatSpeed: 8 },
75
- actions: {
76
- attack: { style: 'bite-lunge' },
77
- eat: { style: 'graze', dropF: 0.1, dropH: 0.0, pitch: 1.6 },
78
- drink: { dropF: 0.12, dropH: 0.0, pitch: 1.6 },
79
- jump: { height: 0.45, distance: 1.0 },
80
- idle: { shift: 0.35, restep: false },
81
- sit: {},
82
- lie: {},
83
- sleep: { style: 'curl' },
84
- },
85
- };
@@ -1,48 +0,0 @@
1
- // Meshing plan: body at 1.85 mm, head (with the thin ears) at 1.1 mm, overlapping across the upper
2
- // neck and cross-faded, eyelid patches at 0.45 mm, and the lower jaw as its own rigid surface.
3
- import { rabbitJoints, HEAD_O } from './rig.js';
4
- import { EYE } from './sculpt.js';
5
- import { eyeFrameOf } from '../../core/sdf/eyeSocket.js';
6
- import { lerp, norm, sub, smoothstep } from '../../core/math/vec.js';
7
-
8
- const J0 = rabbitJoints();
9
- export const NECK_CUT = (() => {
10
- const d = norm(sub(J0.occiput, J0.neckBase));
11
- const c = lerp(J0.neckMid, J0.occiput, 0.3);
12
- return { c, d, band: 0.004 };
13
- })();
14
- export const neckS = (x, y, z) => (x - NECK_CUT.c[0]) * NECK_CUT.d[0] + (y - NECK_CUT.c[1]) * NECK_CUT.d[1] + (z - NECK_CUT.c[2]) * NECK_CUT.d[2];
15
-
16
- export const EYE_PATCH = { R: 0.0135, B: 0.002, h: 0.00045, centres: [1, -1].map((s) => eyeFrameOf(EYE, HEAD_O, s).c) };
17
- export function eyePatchWeight(x, y, z) {
18
- let dmin = 1e9;
19
- for (const c of EYE_PATCH.centres) dmin = Math.min(dmin, Math.hypot(x - c[0], y - c[1], z - c[2]));
20
- return 1 - smoothstep(EYE_PATCH.R - EYE_PATCH.B, EYE_PATCH.R + EYE_PATCH.B, dmin);
21
- }
22
-
23
- export function rabbitRegions(rig, params, Q) {
24
- const B = NECK_CUT.band, r = Q.res;
25
- const patches = Q.eyePatches ? EYE_PATCH.centres.map((c) => ({ c, R: EYE_PATCH.R, B: EYE_PATCH.B, h: EYE_PATCH.h * Math.max(1, r) })) : [];
26
- const lop = !!params.lop;
27
- // lop ears hang below the neck cut: keep them in the finely meshed head region
28
- const sH = lop ? (x, y, z) => Math.max(neckS(x, y, z), Math.min(Math.abs(x) - 0.036, z - 0.1, 0.16 - y)) : neckS;
29
- return {
30
- jobs: [
31
- [{ name: 'body', part: 'body', bmin: [-0.1, -0.012, -0.2], bmax: [0.1, 0.23, 0.15], h: 0.00185 * r, F: 4, clip: (x, y, z) => sH(x, y, z) < B }],
32
- [
33
- { name: 'head', part: 'body', bmin: [-0.075, lop ? 0.09 : 0.12, 0.07], bmax: [0.075, 0.345, 0.225], h: 0.0011 * r, F: 6, clip: (x, y, z) => sH(x, y, z) > -B, patches },
34
- { name: 'jaw', part: 'jaw', bmin: [-0.03, 0.15, 0.115], bmax: [0.03, 0.215, 0.2], h: 0.00105 * r, F: 6, rigidBone: 'jaw' },
35
- ],
36
- ],
37
- fade(x, y, z, name, patch) {
38
- const sN = sH(x, y, z);
39
- if (name === 'body') return 1 - smoothstep(-B, B, sN);
40
- if (name === 'head') {
41
- let f = smoothstep(-B, B, sN);
42
- if (patches.length) { const ew = eyePatchWeight(x, y, z); f *= patch ? ew : 1 - ew; }
43
- return f;
44
- }
45
- return 1;
46
- },
47
- };
48
- }
@@ -1,99 +0,0 @@
1
- // European rabbit (Oryctolagus cuniculus) skeleton in bind pose (metres). Forward = +Z, up = +Y,
2
- // the animal's left = +X.
3
- //
4
- // The bind pose stands with the hind legs half extended (see REAR_LIFT below); the rabbit's resting
5
- // crouch (the loaf: sitting on the haunches, forelegs upright, long hind feet flat on the ground) is
6
- // produced by the engine from it (behaviour.js). When the rabbit moves the hips rise and the heels
7
- // lift (the hind limb pantograph extends), so it hops on its toes.
8
- //
9
- // Wild adult ~1.8 kg, head-body 38 cm: femur 80 mm, tibia 92 mm, tarsus+metatarsus
10
- // 52 mm, hind digits 28 mm (hind foot heel -> claw ~88 mm); scapula 60 mm, humerus 59 mm, radius
11
- // 56 mm, metacarpus 22 mm; head 9 cm; ear 7.5-8.5 cm; tail (scut) ~5 cm.
12
- import { buildRig } from '../../core/rig/rig.js';
13
- import { quadrupedBones, quadrupedLimbs, tailChain } from '../../core/rig/quadruped.js';
14
-
15
- export const TAIL_SEGS = 3;
16
- // head-local origin: on the midline at the height of the eye centres, level with them
17
- export const HEAD_O = [0, 0.219, 0.15];
18
-
19
- // ear pose per variant: erect (wild / most domestic) or lop (hanging beside the cheeks)
20
- export function earTip(params = {}) {
21
- if (params.lop) return [0.05, 0.15, 0.136];
22
- const e = params.earLen || 1;
23
- const base = [0.012, 0.238, 0.122];
24
- const d = [0.017 * e, 0.087 * e, -0.02 * e];
25
- return [base[0] + d[0], base[1] + d[1], base[2] + d[2]];
26
- }
27
-
28
- // The bind pose stands with the hind legs half extended (knee ~77 deg, hips up, back level): the
29
- // halfway point between the folded loaf and the extended push-off, so neither end of the hind
30
- // limb's range stretches the skin far. The rabbit's resting loaf is produced by the engine (the
31
- // hips are lowered at rest, behaviour.js). REAR_LIFT raises the rear of the body with the hips.
32
- export const REAR_LIFT = 0.037;
33
- export const rearW = (z) => { const t = Math.min(1, Math.max(0, (0.03 - z) / 0.12)); return t * t * (3 - 2 * t); };
34
- export const RL = (p) => [p[0], p[1] + REAR_LIFT * rearW(p[2]), p[2]];
35
-
36
- export function rabbitJoints(params = {}) {
37
- const J = {
38
- nose: [0, 0.2, 0.191],
39
- occiput: [0, 0.23, 0.115],
40
- neckMid: [0, 0.205, 0.097],
41
- neckBase: [0, 0.184, 0.076],
42
- chestMid: [0, 0.17, 0.05],
43
- thoraxRear: [0, 0.171, -0.003],
44
- lumbarMid: RL([0, 0.163, -0.052]),
45
- lumbosacral: RL([0, 0.135, -0.092]),
46
- tailBase: RL([0, 0.084, -0.146]),
47
- // forelimb: upright, the elbow tucked against the lower chest
48
- scapTopL: [0.024, 0.178, 0.058],
49
- shoulderL: [0.036, 0.126, 0.1],
50
- elbowL: [0.05, 0.076, 0.064],
51
- wristL: [0.045, 0.022, 0.079],
52
- mcpL: [0.043, 0.0075, 0.094],
53
- ftoeL: [0.043, 0.004, 0.111],
54
- // hind limb half extended: femur 76 mm, tibia 88 mm, knee ~77 deg, heel lifted 16.5 deg (the
55
- // femur's rotation between this pose and the loaf, so the hind-limb pantograph lands the foot
56
- // flat when the hips sit down); toes forward
57
- hipL: [0.031, 0.125, -0.086],
58
- kneeL: [0.05, 0.0762, -0.0277],
59
- hockL: [0.044, 0.0234, -0.0981],
60
- mtpL: [0.044, 0.0085, -0.048],
61
- htoeL: [0.043, 0.0045, -0.02],
62
- snoutBase: [0, 0.208, 0.174],
63
- jawHinge: [0, 0.206, 0.13],
64
- jawTip: [0, 0.185, 0.171],
65
- earBaseL: [0.012, 0.238, 0.122],
66
- earTipL: earTip(params),
67
- };
68
- // the scut: pressed down against the rump (dark upper side out, white underside hidden)
69
- tailChain(J, 'tailBase', [-12, -24, -36], [0.016, 0.016, 0.014]);
70
- return J;
71
- }
72
-
73
- export function rabbitRig(params = {}) {
74
- const J = rabbitJoints(params);
75
- return buildRig({
76
- joints: J,
77
- // characteristic length relative to the cheetah: shoulder height ~0.135 m / 0.76 m
78
- unit: 0.18,
79
- headOrigin: HEAD_O,
80
- bones: quadrupedBones({ tailSegs: TAIL_SEGS, ears: true, jaw: true, extra: [['snout', 'snoutBase', 'nose', 'head', { region: 'head', group: 'snout' }]] }),
81
- axial: {
82
- points: ['nose', 'occiput', 'neckMid', 'neckBase', 'chestMid', 'thoraxRear', 'lumbarMid', 'lumbosacral', 'tailBase', ...Array.from({ length: TAIL_SEGS }, (_, i) => 'tail' + (i + 1))],
83
- bones: ['head', 'neck2', 'neck1', 'chest', 'spine3', 'spine2', 'spine1', 'pelvis', ...Array.from({ length: TAIL_SEGS }, (_, i) => 'tail' + i)],
84
- // the skull reaches back into the nape; the scut takes only its own tuft, not the rump
85
- blend: { 1: [-0.25, 0.3, 1.0], 2: [-0.12, 0.12], 8: [0.03, 0.09] },
86
- },
87
- limbs: quadrupedLimbs({
88
- front: { tCore: 0.9, aCore: 0.07, aBody: 0.05, midX: 0.0 },
89
- hind: params.hindField || { tCore: 1.0, aCore: 0.12, aBody: 0.1, midX: 0.01 },
90
- }),
91
- appendages: [
92
- { group: 'earL', bone: 'earL', blend: [-0.06, 0.08] },
93
- { group: 'earR', bone: 'earR', blend: [-0.06, 0.08] },
94
- { group: 'snout', bone: 'snout', blend: [-0.004, 0.01] },
95
- ],
96
- webTags: ['flankfold', 'thighfront', 'scapmuscle'],
97
- });
98
- }
99
-