wobnimo 0.1.4 → 0.2.0

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 (68) hide show
  1. package/AGENTS.md +18 -4
  2. package/README.md +38 -7
  3. package/dist/characters/bao.d.ts +6 -0
  4. package/dist/characters/bao.js +1 -0
  5. package/dist/characters/berry.d.ts +6 -0
  6. package/dist/characters/berry.js +1 -0
  7. package/dist/characters/boo.js +1 -1
  8. package/dist/characters/bumble.d.ts +6 -0
  9. package/dist/characters/bumble.js +1 -0
  10. package/dist/characters/cacti.d.ts +6 -0
  11. package/dist/characters/cacti.js +1 -0
  12. package/dist/characters/cap.d.ts +6 -0
  13. package/dist/characters/cap.js +1 -0
  14. package/dist/characters/drift.d.ts +6 -0
  15. package/dist/characters/drift.js +1 -0
  16. package/dist/characters/ember.d.ts +6 -0
  17. package/dist/characters/ember.js +1 -0
  18. package/dist/characters/hop.d.ts +6 -0
  19. package/dist/characters/hop.js +1 -0
  20. package/dist/characters/index.d.ts +11 -1
  21. package/dist/characters/index.js +11 -11
  22. package/dist/characters/inky.js +1 -1
  23. package/dist/characters/latte.d.ts +6 -0
  24. package/dist/characters/latte.js +1 -0
  25. package/dist/characters/microduck.js +1 -1
  26. package/dist/characters/miso.js +1 -1
  27. package/dist/characters/mochi.js +1 -1
  28. package/dist/characters/pebble.js +1 -1
  29. package/dist/characters/pip.js +1 -1
  30. package/dist/characters/rex.js +1 -1
  31. package/dist/characters/swirl.d.ts +6 -0
  32. package/dist/characters/swirl.js +1 -0
  33. package/dist/characters/tad.js +1 -1
  34. package/dist/characters/volt.js +1 -1
  35. package/dist/cli.js +1888 -0
  36. package/dist/element.d.ts +1 -1
  37. package/dist/element.js +9 -9
  38. package/dist/index-Cm5wWKoT.d.ts +12 -0
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +6 -6
  41. package/dist/react.js +16 -16
  42. package/dist/wobnimo.js +12 -12
  43. package/package.json +14 -4
  44. package/skill/SKILL.md +719 -0
  45. package/skill/examples/bao.ts +73 -0
  46. package/skill/examples/berry.ts +97 -0
  47. package/skill/examples/boo.ts +87 -0
  48. package/skill/examples/bumble.ts +70 -0
  49. package/skill/examples/cacti.ts +79 -0
  50. package/skill/examples/cap.ts +59 -0
  51. package/skill/examples/drift.ts +74 -0
  52. package/skill/examples/ember.ts +78 -0
  53. package/skill/examples/hop.ts +66 -0
  54. package/skill/examples/inky.ts +168 -0
  55. package/skill/examples/latte.ts +73 -0
  56. package/skill/examples/microduck.ts +222 -0
  57. package/skill/examples/miso.ts +182 -0
  58. package/skill/examples/mochi.ts +78 -0
  59. package/skill/examples/pebble.ts +174 -0
  60. package/skill/examples/pip.ts +170 -0
  61. package/skill/examples/rex.ts +193 -0
  62. package/skill/examples/swirl.ts +69 -0
  63. package/skill/examples/tad.ts +117 -0
  64. package/skill/examples/volt.ts +214 -0
  65. package/skill/reference/recipes.md +551 -0
  66. package/skill/reference/spec.md +258 -0
  67. package/skill/templates/starter.ts +73 -0
  68. package/dist/index-DRDEWSGV.d.ts +0 -8
@@ -0,0 +1,193 @@
1
+ import type { BoneSpec, CharacterSpec, PaintSpec, PartSpec } from 'wobnimo';
2
+
3
+ /* The soft back spikes: one jiggling bone each, running from the crown down the tail. */
4
+ const SPIKES: Array<{ parent: string; at: [number, number, number]; tilt: number; size: number }> = [
5
+ { parent: 'head', at: [0, 0.43, 0.05], tilt: -0.1, size: 0.075 },
6
+ { parent: 'head', at: [0, 0.41, -0.1], tilt: -0.5, size: 0.09 },
7
+ { parent: 'head', at: [0, 0.3, -0.24], tilt: -1.0, size: 0.085 },
8
+ { parent: 'body', at: [0, 0.5, -0.24], tilt: -1.2, size: 0.08 },
9
+ { parent: 'body', at: [0, 0.34, -0.3], tilt: -1.45, size: 0.07 },
10
+ { parent: 'tail0', at: [0, 0.12, 0.07], tilt: 0, size: 0.06 },
11
+ { parent: 'tail1', at: [0, 0.1, 0.05], tilt: 0, size: 0.045 },
12
+ ];
13
+
14
+ /** A baby T. rex: pebbly scales, a toothless grin, tiny arms and a tail that wags. */
15
+ export const rex: CharacterSpec = {
16
+ id: 'rex',
17
+ name: 'Rex',
18
+ tagline: 'A baby T. rex with pebbly scales, wobbly back spikes, tiny arms and a wagging tail',
19
+ accent: '#4fb86a',
20
+ frame: { target: 0.52, radius: 0.76 },
21
+ bound: { y: 0.46, radius: 0.86 },
22
+ motion: { hop: 0.15, squash: 1.15, snap: 1.05, talkSquash: 0.35 },
23
+ materials: {
24
+ /* a soft vinyl-toy hide: satin, with pebbled scales and darker seams */
25
+ hide: {
26
+ color: '#78cf7f', f0: 0.04, spec: 0.7, shininess: 40, rim: 0.7, gloss: 0.35, sss: 0.2, sssColor: '#c8ffb0',
27
+ surface: { kind: 'scales', scale: 24, strength: 0.5, color: '#4b9f5d', bone: 'head' },
28
+ },
29
+ bodyHide: {
30
+ color: '#78cf7f', shadeOf: 'hide', f0: 0.04, spec: 0.7, shininess: 40, rim: 0.7, gloss: 0.35, sss: 0.2, sssColor: '#c8ffb0',
31
+ surface: { kind: 'scales', scale: 24, strength: 0.5, color: '#4b9f5d' },
32
+ },
33
+ belly: { color: '#fff0c4', f0: 0.04, spec: 0.5, shininess: 30, rim: 0.5, gloss: 0.3, sss: 0.25, sssColor: '#fff6d8' },
34
+ spike: { color: '#ff9b4a', f0: 0.05, spec: 0.9, shininess: 60, rim: 0.5, gloss: 0.5, sss: 0.35, sssColor: '#ffc58f' },
35
+ claw: { color: '#fff6e2', f0: 0.05, spec: 1, shininess: 80, rim: 0.3, gloss: 0.6 },
36
+ },
37
+ bones: [
38
+ { name: 'body', pivot: [0, 0, 0], drive: { ry: [['yaw', 0.25]], rz: [['roll', 0.3]] } },
39
+ { name: 'head', parent: 'body', pivot: [0, 0.56, 0.06], drive: { rx: [['pitch', -1]], ry: [['yaw', 0.8]], rz: [['roll', 0.7]] } },
40
+ /* tiny arms, held up in front of the chest */
41
+ { name: 'armL', parent: 'body', pivot: [-0.15, 0.42, 0.25], rest: { rx: -0.6 }, drive: { rx: [['flap', -0.9]], rz: [['flap', -0.5]] } },
42
+ { name: 'armR', parent: 'body', pivot: [0.15, 0.42, 0.25], rest: { rx: -0.6 }, drive: { rx: [['flap', -0.9]], rz: [['flap', 0.5]] } },
43
+ /* the tail sweeps out behind and to the side, so it shows from the front */
44
+ { name: 'tail0', parent: 'body', pivot: [0.08, 0.17, -0.24], rest: { rx: -1.25, rz: -0.6 }, wave: { rz: [0.2, 0.5, 0] }, jiggle: { axis: [0, 1, 0], length: 0.18, freq: 2.2, damping: 0.25, maxAngle: 0.6 } },
45
+ { name: 'tail1', parent: 'tail0', pivot: [0, 0.18, 0], rest: { rx: 0.2 }, wave: { rz: [0.2, 0.5, 0.8] }, jiggle: { axis: [0, 1, 0], length: 0.15, freq: 2, damping: 0.22, maxAngle: 0.7 } },
46
+ { name: 'tail2', parent: 'tail1', pivot: [0, 0.15, 0], rest: { rx: 0.15 }, wave: { rz: [0.25, 0.5, 1.6] }, jiggle: { axis: [0, 1, 0], length: 0.12, freq: 1.8, damping: 0.2, maxAngle: 0.8 } },
47
+ ...SPIKES.map(({ parent, at, tilt }, i): BoneSpec => ({
48
+ name: `spike${i}`, parent, pivot: at, rest: { rx: tilt },
49
+ jiggle: { axis: [0, 1, 0], length: 0.08, freq: 4 + i * 0.3, damping: 0.12, maxAngle: 0.45 },
50
+ })),
51
+ ],
52
+ parts: [
53
+ /* a pear of a body on two chunky thighs */
54
+ { bone: 'body', shape: 'ellipsoid', at: [0, 0.3, -0.02], radii: [0.3, 0.3, 0.28], material: 'bodyHide' },
55
+ { bone: 'body', shape: 'ellipsoid', at: [-0.19, 0.15, -0.02], radii: [0.13, 0.15, 0.17], blend: 0.08, material: 'bodyHide' },
56
+ { bone: 'body', shape: 'ellipsoid', at: [0.19, 0.15, -0.02], radii: [0.13, 0.15, 0.17], blend: 0.08, material: 'bodyHide' },
57
+ /* feet with three blunt claws each */
58
+ ...[-1, 1].flatMap((s): PartSpec[] => [
59
+ { bone: 'body', shape: 'ellipsoid', at: [s * 0.2, 0.045, 0.1], radii: [0.1, 0.05, 0.13], blend: 0.05, material: 'bodyHide' },
60
+ ...[-1, 0, 1].map((t): PartSpec => ({
61
+ bone: 'body', shape: 'ellipsoid', at: [s * 0.2 + t * 0.05, 0.03, 0.225 - Math.abs(t) * 0.015], radii: [0.022, 0.022, 0.026], blend: 0.012, material: 'claw',
62
+ })),
63
+ ]),
64
+ /* a big round head with a wide, soft snout */
65
+ { bone: 'head', shape: 'ellipsoid', at: [0, 0.2, -0.02], radii: [0.29, 0.25, 0.27], blend: 0.12, material: 'hide' },
66
+ { bone: 'head', shape: 'ellipsoid', at: [0, 0.1, 0.17], radii: [0.23, 0.14, 0.18], blend: 0.1, material: 'hide' },
67
+ /* nostrils */
68
+ { bone: 'head', shape: 'sphere', at: [-0.047, 0.162, 0.322], radius: 0.014, op: 'sub', blend: 0.01, material: 'hide' },
69
+ { bone: 'head', shape: 'sphere', at: [0.047, 0.162, 0.322], radius: 0.014, op: 'sub', blend: 0.01, material: 'hide' },
70
+ /* tiny arms with two little claws */
71
+ ...([['armL', -1], ['armR', 1]] as const).flatMap(([bone, s]): PartSpec[] => [
72
+ { bone, shape: 'capsule', from: [0, 0, 0], to: [s * 0.01, -0.1, 0.03], radius: 0.042, blend: 0.04, material: 'bodyHide' },
73
+ { bone, shape: 'sphere', at: [s * -0.014, -0.135, 0.05], radius: 0.015, blend: 0.01, material: 'claw' },
74
+ { bone, shape: 'sphere', at: [s * 0.02, -0.135, 0.045], radius: 0.015, blend: 0.01, material: 'claw' },
75
+ ]),
76
+ /* the tail, tapering */
77
+ { bone: 'tail0', shape: 'roundCone', from: [0, 0, 0], to: [0, 0.18, 0], r1: 0.12, r2: 0.09, blend: 0.06, material: 'bodyHide' },
78
+ { bone: 'tail1', shape: 'roundCone', from: [0, 0, 0], to: [0, 0.15, 0], r1: 0.09, r2: 0.06, blend: 0.03, material: 'bodyHide' },
79
+ { bone: 'tail2', shape: 'roundCone', from: [0, 0, 0], to: [0, 0.12, 0], r1: 0.06, r2: 0.03, blend: 0.03, material: 'bodyHide' },
80
+ /* soft orange spikes */
81
+ ...SPIKES.map(({ size }, i): PartSpec => ({
82
+ bone: `spike${i}`, shape: 'roundCone', from: [0, -0.02, 0], to: [0, size * 1.1, 0], r1: size * 0.65, r2: size * 0.15, blend: 0.025, material: 'spike',
83
+ })),
84
+ ],
85
+ paints: [
86
+ /* a cream belly and chin, freckles on the snout, blushing cheeks */
87
+ { bone: 'body', on: ['bodyHide'], kind: 'ellipse', at: [0, 0.24, 0.08], radii: [0.16, 0.2], color: '#fff0c4', soft: 0.2 },
88
+ { bone: 'head', on: ['hide'], kind: 'ellipse', at: [0, -0.01, 0.15], radii: [0.17, 0.06], color: '#fff0c4', soft: 0.35 },
89
+ { bone: 'head', on: ['hide'], kind: 'sphere', at: [-0.2, 0.12, 0.24], radius: 0.055, color: '#ff9a9a', soft: 0.6, opacity: 0.7 },
90
+ { bone: 'head', on: ['hide'], kind: 'sphere', at: [0.2, 0.12, 0.24], radius: 0.055, color: '#ff9a9a', soft: 0.6, opacity: 0.7 },
91
+ ...[[-0.083, 0.204, 0.289], [-0.109, 0.181, 0.297], [0.083, 0.204, 0.289], [0.109, 0.181, 0.297]].map(([x, y, z]): PaintSpec => ({
92
+ bone: 'head', on: ['hide'], kind: 'sphere', at: [x, y, z], radius: 0.009, color: '#3f8a4f', soft: 0.3,
93
+ })),
94
+ ],
95
+ eyes: {
96
+ kind: 'ball',
97
+ bone: 'head',
98
+ at: [[-0.13, 0.26, 0.19], [0.13, 0.26, 0.19]],
99
+ radius: 0.085,
100
+ iris: '#e0942f',
101
+ irisSize: 0.78,
102
+ pupilSize: 0.46,
103
+ pupilAspect: 0.75,
104
+ lid: 'hide',
105
+ },
106
+ /* a wide, toothless grin across the snout */
107
+ face: {
108
+ kind: 'mouth',
109
+ bone: 'head',
110
+ on: ['hide'],
111
+ at: [0, 0.06, 0.34],
112
+ width: 0.1,
113
+ color: '#5b1f2b',
114
+ tongue: '#ff7f93',
115
+ },
116
+ anchors: {
117
+ top: { bone: 'head', at: [0.16, 0.44, 0.06] },
118
+ mouth: { bone: 'head', at: [0, 0.06, 0.37] },
119
+ ear: { bone: 'head', at: [-0.3, 0.22, 0] },
120
+ feet: { bone: 'root', at: [0, 0.02, 0.15] },
121
+ tail: { bone: 'tail2', at: [0, 0.12, 0] },
122
+ },
123
+ acting: {
124
+ idle: { tail0: { rz: [-0.6, 0.12, 0.45, 0] } },
125
+ /* a tiny claw tapping the chin, which it can't quite reach */
126
+ thinking: {
127
+ armR: { rx: [-1.3, 0.08, 2.5, 0], rz: 0.3 },
128
+ tail2: { rx: [0.15, 0.3, 1.4, 0] },
129
+ },
130
+ listening: {
131
+ armL: { rx: -1.1, rz: -0.6 },
132
+ tail0: { rz: -0.4 },
133
+ },
134
+ speaking: {
135
+ armL: { rx: [-0.6, 0.25, 1.6, 0] },
136
+ armR: { rx: [-0.6, 0.25, 1.6, 2] },
137
+ tail0: { rz: [-0.6, 0.18, 0.9, 0] },
138
+ },
139
+ /* curled up: arms tucked, the tail wrapped round the front */
140
+ sleeping: {
141
+ armL: { rx: 0.1, rz: 0.2 },
142
+ armR: { rx: 0.1, rz: -0.2 },
143
+ tail0: { rz: -1.3, rx: -1.0 },
144
+ tail1: { rx: 0.4 },
145
+ },
146
+ /* scribbling with both little hands */
147
+ working: {
148
+ armL: { rx: [-0.9, 0.15, 7, 0] },
149
+ armR: { rx: [-0.9, 0.15, 7, Math.PI] },
150
+ head: { rx: 0.12 },
151
+ tail2: { rx: [0.15, 0.2, 2, 0] },
152
+ },
153
+ /* arms flailing, tail stiff, every spike on end */
154
+ error: {
155
+ armL: { rx: [-1.6, 0.35, 9, 0], rz: -0.4 },
156
+ armR: { rx: [-1.6, 0.35, 9, 1.4], rz: 0.4 },
157
+ tail0: { rz: [-0.5, 0.06, 12, 0], rx: -1.45 },
158
+ spike1: { rx: -0.2 },
159
+ spike2: { rx: -0.6 },
160
+ spike3: { rx: -0.8 },
161
+ },
162
+ surprised: {
163
+ armL: { rx: -1.9, rz: -0.6 },
164
+ armR: { rx: -1.9, rz: 0.6 },
165
+ tail0: { rx: -1.5 },
166
+ },
167
+ /* a happy stomp with tiny arms in the air and a wagging tail */
168
+ celebrating: {
169
+ armL: { rx: [-2.2, 0.3, 4, 0], rz: -0.5 },
170
+ armR: { rx: [-2.2, 0.3, 4, Math.PI], rz: 0.5 },
171
+ tail0: { rz: [-0.6, 0.55, 3, 0] },
172
+ },
173
+ sad: {
174
+ armL: { rx: 0.2 },
175
+ armR: { rx: 0.2 },
176
+ tail0: { rx: -0.95, rz: -0.4 },
177
+ tail1: { rx: 0.35 },
178
+ },
179
+ happy: {
180
+ armL: { rx: [-1.4, 0.4, 6, 0] },
181
+ armR: { rx: [-1.4, 0.4, 6, 1.4] },
182
+ tail0: { rz: [-0.6, 0.5, 4, 0] },
183
+ },
184
+ },
185
+ fx: {
186
+ /* a little roar on surprise */
187
+ 'enter:surprised': [
188
+ { glyph: 'arc', anchor: 'mouth', rate: 3, offset: [0.08, 0, 0.05], mirror: true, velocity: [0.3, 0.05, 0.1], jitter: 0.04, life: [0.5, 0.6], size: [0.04, 0.11], color: '#7fd18a' },
189
+ ],
190
+ },
191
+ };
192
+
193
+ export default rex;
@@ -0,0 +1,69 @@
1
+ import type { CharacterSpec, PartSpec } from 'wobnimo';
2
+
3
+ /** A snail whose shell looks like a cinnamon roll. */
4
+ export const swirl: CharacterSpec = {
5
+ id: 'swirl',
6
+ name: 'Swirl',
7
+ tagline: 'A slow, sweet snail carrying a glazed cinnamon roll for a shell',
8
+ accent: '#c27a3e',
9
+ frame: { target: 0.38, radius: 0.59 },
10
+ bound: { y: 0.35, radius: 0.6 },
11
+ motion: { hop: 0.03, squash: 1.4, snap: 0.7, talkSquash: 0.6 },
12
+ materials: {
13
+ skin: { color: '#b9d97a', f0: 0.06, spec: 1.4, shininess: 110, rim: 0.7, sss: 0.45, sssColor: '#e6ffb0', gloss: 0.8, surface: { kind: 'ripple', scale: 18, strength: 0.25 } },
14
+ dough: { color: '#d9944f', f0: 0.03, spec: 0.5, shininess: 30, rim: 0.5, sheen: 0.3 },
15
+ cinnamon: { color: '#8a4b22', shadeOf: 'dough', f0: 0.03, spec: 0.5, shininess: 30, rim: 0.4 },
16
+ glaze: { color: '#fff4e4', f0: 0.08, spec: 1.6, shininess: 160, rim: 0.6, sss: 0.4, sssColor: '#ffffff', gloss: 0.9 },
17
+ bead: { color: '#1a1410', f0: 0.06, spec: 2.2, shininess: 400, rim: 0.2, gloss: 1 },
18
+ },
19
+ bones: [
20
+ { name: 'body', pivot: [0, 0.053, 0], drive: { ry: [['yaw', 0.3]], rz: [['roll', 0.3]] }, wave: { rz: [0.02, 0.4, 0] } },
21
+ /* the head rises out of the foot at the front */
22
+ { name: 'head', parent: 'body', pivot: [0.24, 0.12, 0.08], drive: { rx: [['pitch', -0.7]], ry: [['yaw', 0.7]], rz: [['roll', 0.6]] } },
23
+ { name: 'stalkL', parent: 'head', pivot: [-0.06, 0.3, 0.02], rest: { rz: 0.3 }, jiggle: { axis: [0, 1, 0], length: 0.16, freq: 2.4, damping: 0.12 } },
24
+ { name: 'stalkR', parent: 'head', pivot: [0.06, 0.3, 0.02], rest: { rz: -0.3 }, jiggle: { axis: [0, 1, 0], length: 0.16, freq: 2.4, damping: 0.12 } },
25
+ { name: 'shell', parent: 'body', pivot: [-0.08, 0.12, -0.04], wave: { rz: [0.015, 0.4, 1] } },
26
+ ],
27
+ parts: [
28
+ /* a long soft foot */
29
+ { bone: 'body', shape: 'ellipsoid', at: [0, 0.07, 0], radii: [0.42, 0.08, 0.2], material: 'skin' },
30
+ /* the head and neck */
31
+ { bone: 'head', shape: 'capsule', from: [0, -0.05, 0], to: [0, 0.2, 0.02], radius: 0.13, blend: 0.08, material: 'skin' },
32
+ { bone: 'stalkL', shape: 'capsule', from: [0, 0, 0], to: [0, 0.14, 0], radius: 0.02, material: 'skin' },
33
+ { bone: 'stalkL', shape: 'sphere', at: [0, 0.15, 0], radius: 0.035, material: 'skin' },
34
+ { bone: 'stalkR', shape: 'capsule', from: [0, 0, 0], to: [0, 0.14, 0], radius: 0.02, material: 'skin' },
35
+ { bone: 'stalkR', shape: 'sphere', at: [0, 0.15, 0], radius: 0.035, material: 'skin' },
36
+ /* the shell: a cinnamon roll on its side, a spiral of dough and a lick of glaze */
37
+ { bone: 'shell', shape: 'cylinder', at: [0, 0.27, 0], rot: [Math.PI / 2, 0, 0], radius: 0.27, half: 0.13, round: 0.07, material: 'dough' },
38
+ /* the spiral: alternately carve a groove and fill the next ring back in, outside to centre
39
+ (a subtraction only cuts what comes before it, so the order is the pattern) */
40
+ ...[0.21, 0.15, 0.09].flatMap((r, i): PartSpec[] => [
41
+ { bone: 'shell', shape: 'cylinder', at: [0.01 * i, 0.27 + 0.01 * i, 0.12], rot: [Math.PI / 2, 0, 0], radius: r, half: 0.03, round: 0.02, op: 'sub', blend: 0.015, material: 'cinnamon' },
42
+ { bone: 'shell', shape: 'cylinder', at: [0.01 * i, 0.27 + 0.01 * i, 0.1], rot: [Math.PI / 2, 0, 0], radius: r - 0.03, half: 0.03, round: 0.025, blend: 0.01, material: 'dough' },
43
+ ]),
44
+ { bone: 'shell', shape: 'ellipsoid', at: [-0.04, 0.47, 0.03], radii: [0.2, 0.06, 0.15], blend: 0.03, material: 'glaze' },
45
+ ],
46
+ paints: [
47
+ { bone: 'head', on: ['skin'], kind: 'sphere', at: [-0.09, 0.06, 0.1], radius: 0.035, color: '#ff9eb0', soft: 0.6, opacity: 0.8 },
48
+ { bone: 'head', on: ['skin'], kind: 'sphere', at: [0.09, 0.06, 0.1], radius: 0.035, color: '#ff9eb0', soft: 0.6, opacity: 0.8 },
49
+ ],
50
+ eyes: { kind: 'bead', bone: 'head', at: [[-0.055, 0.14, 0.128], [0.055, 0.14, 0.128]], radii: [0.026, 0.038, 0.018], material: 'bead' },
51
+ face: { kind: 'mouth', bone: 'head', on: ['skin'], at: [0, 0.05, 0.14], width: 0.04, color: '#3d4f1c', tongue: '#ff8a9a' },
52
+ anchors: {
53
+ top: { bone: 'shell', at: [0, 0.58, 0] },
54
+ mouth: { bone: 'head', at: [0, 0.05, 0.16] },
55
+ ear: { bone: 'head', at: [-0.14, 0.15, 0] },
56
+ feet: { bone: 'root', at: [0.3, 0.02, 0.12] },
57
+ },
58
+ acting: {
59
+ thinking: { head: { rz: 0.2 }, stalkL: { rz: 0.6 } },
60
+ listening: { stalkL: { rx: -0.4 }, stalkR: { rx: -0.4 } },
61
+ sleeping: { head: { rx: 0.5 }, stalkL: { rx: 1.1 }, stalkR: { rx: 1.1 } },
62
+ error: { stalkL: { rz: [0.3, 0.3, 8, 0] }, stalkR: { rz: [-0.3, 0.3, 8, 1] } },
63
+ surprised: { stalkL: { rz: 0.05 }, stalkR: { rz: -0.05 }, head: { rx: -0.2 } },
64
+ celebrating: { stalkL: { rz: [0.4, 0.3, 4, 0] }, stalkR: { rz: [-0.4, 0.3, 4, Math.PI] } },
65
+ sad: { head: { rx: 0.3 }, stalkL: { rx: 1.2, rz: 0.5 }, stalkR: { rx: 1.2, rz: -0.5 } },
66
+ },
67
+ };
68
+
69
+ export default swirl;
@@ -0,0 +1,117 @@
1
+ import type { CharacterSpec } from 'wobnimo';
2
+
3
+ /** A tree frog: wet, glossy and spotted, with eyes on top and a throat that puffs when it talks. */
4
+ export const tad: CharacterSpec = {
5
+ id: 'tad',
6
+ name: 'Tad',
7
+ tagline: 'A glossy tree frog with a wet sheen, eyes on top and a throat that puffs as it talks',
8
+ accent: '#3fae4a',
9
+ frame: { target: 0.42, radius: 0.66 },
10
+ bound: { y: 0.4, radius: 0.72 },
11
+ motion: { hop: 0.26, squash: 1.6, snap: 1.2, look: 0.8, talkSquash: 0.45 },
12
+ materials: {
13
+ /* wet skin: a strong, sharp clear coat over a little translucency */
14
+ skin: {
15
+ color: '#5fc24e', f0: 0.07, spec: 2, shininess: 260, rim: 0.7, gloss: 0.95, sss: 0.3, sssColor: '#c6ff8f',
16
+ surface: { kind: 'speckle', scale: 9, strength: 0.85, color: '#2f8a3a', bone: 'head' },
17
+ },
18
+ bodySkin: {
19
+ color: '#5fc24e', shadeOf: 'skin', f0: 0.07, spec: 2, shininess: 260, rim: 0.7, gloss: 0.95, sss: 0.3, sssColor: '#c6ff8f',
20
+ surface: { kind: 'speckle', scale: 9, strength: 0.85, color: '#2f8a3a' },
21
+ },
22
+ belly: { color: '#f3f0b6', f0: 0.06, spec: 1.6, shininess: 200, rim: 0.5, gloss: 0.9, sss: 0.45, sssColor: '#fffbd0' },
23
+ toe: { color: '#ffb54a', f0: 0.06, spec: 1.4, shininess: 160, rim: 0.4, gloss: 0.8, sss: 0.3, sssColor: '#ffd99a' },
24
+ },
25
+ bones: [
26
+ { name: 'body', pivot: [0, 0, 0], drive: { ry: [['yaw', 0.25]], rz: [['roll', 0.3]] } },
27
+ /* frogs have no neck: the whole top of the body tips and turns */
28
+ { name: 'head', parent: 'body', pivot: [0, 0.3, 0.02], drive: { rx: [['pitch', -0.8]], ry: [['yaw', 0.7]], rz: [['roll', 0.6]] } },
29
+ /* the throat sac swings forward and out from under the chin as it talks */
30
+ { name: 'throat', parent: 'head', pivot: [0, 0.02, 0.12], drive: { rx: [['talk', 0.9]] } },
31
+ { name: 'armL', parent: 'body', pivot: [-0.22, 0.2, 0.18], drive: { rz: [['flap', -1.3]], rx: [['flap', -0.4]] } },
32
+ { name: 'armR', parent: 'body', pivot: [0.22, 0.2, 0.18], drive: { rz: [['flap', 1.3]], rx: [['flap', -0.4]] } },
33
+ ],
34
+ parts: [
35
+ /* a squat, pear-shaped body with folded back legs */
36
+ { bone: 'body', shape: 'ellipsoid', at: [0, 0.22, -0.03], radii: [0.36, 0.22, 0.32], material: 'bodySkin' },
37
+ { bone: 'body', shape: 'ellipsoid', at: [-0.3, 0.12, -0.04], rot: [0, 0.25, 0], radii: [0.13, 0.11, 0.22], blend: 0.09, material: 'bodySkin' },
38
+ { bone: 'body', shape: 'ellipsoid', at: [0.3, 0.12, -0.04], rot: [0, -0.25, 0], radii: [0.13, 0.11, 0.22], blend: 0.09, material: 'bodySkin' },
39
+ /* webbed back feet, splayed */
40
+ { bone: 'body', shape: 'ellipsoid', at: [-0.33, 0.025, 0.16], rot: [0, 0.5, 0], radii: [0.08, 0.025, 0.13], blend: 0.03, material: 'bodySkin' },
41
+ { bone: 'body', shape: 'ellipsoid', at: [0.33, 0.025, 0.16], rot: [0, -0.5, 0], radii: [0.08, 0.025, 0.13], blend: 0.03, material: 'bodySkin' },
42
+ /* the wide head, with two domes for the eyes */
43
+ { bone: 'head', shape: 'ellipsoid', at: [0, 0.1, 0.05], radii: [0.38, 0.19, 0.31], blend: 0.14, material: 'skin' },
44
+ { bone: 'head', shape: 'sphere', at: [-0.19, 0.24, 0.1], radius: 0.13, blend: 0.07, material: 'skin' },
45
+ { bone: 'head', shape: 'sphere', at: [0.19, 0.24, 0.1], radius: 0.13, blend: 0.07, material: 'skin' },
46
+ /* the throat sac: hidden under the chin at rest */
47
+ { bone: 'throat', shape: 'ellipsoid', at: [0, -0.04, 0.1], radii: [0.14, 0.1, 0.12], blend: 0.05, material: 'belly' },
48
+ /* little arms with round toe pads */
49
+ { bone: 'armL', shape: 'capsule', from: [0, 0, 0], to: [-0.03, -0.17, 0.08], radius: 0.045, blend: 0.05, material: 'bodySkin' },
50
+ { bone: 'armL', shape: 'sphere', at: [-0.07, -0.19, 0.12], radius: 0.026, blend: 0.02, material: 'toe' },
51
+ { bone: 'armL', shape: 'sphere', at: [-0.02, -0.19, 0.15], radius: 0.026, blend: 0.02, material: 'toe' },
52
+ { bone: 'armL', shape: 'sphere', at: [0.03, -0.19, 0.13], radius: 0.026, blend: 0.02, material: 'toe' },
53
+ { bone: 'armR', shape: 'capsule', from: [0, 0, 0], to: [0.03, -0.17, 0.08], radius: 0.045, blend: 0.05, material: 'bodySkin' },
54
+ { bone: 'armR', shape: 'sphere', at: [0.07, -0.19, 0.12], radius: 0.026, blend: 0.02, material: 'toe' },
55
+ { bone: 'armR', shape: 'sphere', at: [0.02, -0.19, 0.15], radius: 0.026, blend: 0.02, material: 'toe' },
56
+ { bone: 'armR', shape: 'sphere', at: [-0.03, -0.19, 0.13], radius: 0.026, blend: 0.02, material: 'toe' },
57
+ ],
58
+ paints: [
59
+ { bone: 'body', on: ['bodySkin'], kind: 'ellipse', at: [0, 0.16, 0.28], radii: [0.22, 0.13], color: '#f3f0b6', soft: 0.3 },
60
+ { bone: 'head', on: ['skin'], kind: 'ellipse', at: [0, -0.01, 0.34], radii: [0.2, 0.06], color: '#f3f0b6', soft: 0.4 },
61
+ { bone: 'head', on: ['skin'], kind: 'sphere', at: [-0.24, 0.07, 0.27], radius: 0.055, color: '#ff8f9c', soft: 0.6, opacity: 0.7 },
62
+ { bone: 'head', on: ['skin'], kind: 'sphere', at: [0.24, 0.07, 0.27], radius: 0.055, color: '#ff8f9c', soft: 0.6, opacity: 0.7 },
63
+ ],
64
+ eyes: {
65
+ kind: 'ball',
66
+ bone: 'head',
67
+ at: [[-0.19, 0.27, 0.15], [0.19, 0.27, 0.15]],
68
+ radius: 0.1,
69
+ iris: '#e7b93a',
70
+ irisSize: 0.74,
71
+ pupilSize: 0.36,
72
+ pupilAspect: 1.8,
73
+ lid: 'skin',
74
+ },
75
+ /* a frog's mouth runs nearly ear to ear */
76
+ face: {
77
+ kind: 'mouth',
78
+ bone: 'head',
79
+ on: ['skin'],
80
+ at: [0, 0.06, 0.34],
81
+ width: 0.12,
82
+ color: '#5a1f2e',
83
+ tongue: '#ff7b93',
84
+ },
85
+ anchors: {
86
+ top: { bone: 'head', at: [0.2, 0.36, 0.05] },
87
+ mouth: { bone: 'head', at: [0, 0.05, 0.37] },
88
+ ear: { bone: 'head', at: [-0.38, 0.12, 0] },
89
+ feet: { bone: 'root', at: [0, 0.03, 0.22] },
90
+ },
91
+ acting: {
92
+ idle: { throat: { rx: [0, 0.12, 1.1, 0] } },
93
+ /* a toe to the chin */
94
+ thinking: { armR: { rz: 0.6, rx: -1.5 } },
95
+ listening: { armL: { rz: -1.6, rx: -0.4 } },
96
+ speaking: {
97
+ armL: { rx: [-0.25, 0.2, 1.3, 0] },
98
+ armR: { rx: [-0.25, 0.2, 1.3, 2] },
99
+ },
100
+ sleeping: { armL: { rx: 0.2 }, armR: { rx: 0.2 }, throat: { rx: [0.2, 0.25, 0.18, 0] } },
101
+ /* drumming its toes */
102
+ working: { armL: { rx: [-0.5, 0.2, 7, 0] }, armR: { rx: [-0.5, 0.2, 7, Math.PI] }, throat: { rx: [0, 0.15, 3.5, 0] } },
103
+ error: { armL: { rz: [-1.2, 0.15, 12, 0] }, armR: { rz: [1.2, 0.15, 12, 1] }, throat: { rx: 0.6 } },
104
+ surprised: { armL: { rz: -1.8 }, armR: { rz: 1.8 }, throat: { rx: 0.9 } },
105
+ celebrating: { armL: { rz: [-2, 0.4, 4, 0] }, armR: { rz: [2, 0.4, 4, Math.PI] }, throat: { rx: [0.4, 0.4, 4, 0] } },
106
+ sad: { armL: { rz: 0.2, rx: 0.3 }, armR: { rz: -0.2, rx: 0.3 } },
107
+ happy: { armL: { rz: [-1.5, 0.4, 5, 0] }, armR: { rz: [1.5, 0.4, 5, 1] }, throat: { rx: [0.4, 0.4, 5, 0] } },
108
+ },
109
+ fx: {
110
+ replace: ['land'],
111
+ /* a splash every time it lands, and a ribbit of bubbles */
112
+ land: [{ glyph: 'drop', anchor: 'feet', rate: 8, spread: 0.2, velocity: [0, 0.7, 0.05], jitter: 0.7, gravity: 3.2, life: [0.45, 0.6], size: [0.035, 0.022], color: '#7fd0ff', align: true }],
113
+ syllable: [{ glyph: 'bubble', anchor: 'mouth', rate: 1, offset: [0.1, 0, 0.02], velocity: [0.08, 0.18, 0.05], jitter: 0.08, wobble: 0.05, life: [0.9, 1.2], size: [0.016, 0.036], color: '#a6e8ff' }],
114
+ },
115
+ };
116
+
117
+ export default tad;
@@ -0,0 +1,214 @@
1
+ import type { BoneSpec, CharacterSpec, PartSpec } from 'wobnimo';
2
+
3
+ /* A jointed arm: shoulder, elbow, and a claw hand. `side` is -1 for the
4
+ arm on screen left, 1 for screen right. */
5
+ function arm(side: -1 | 1): BoneSpec[] {
6
+ const s = side < 0 ? 'L' : 'R';
7
+ return [
8
+ { name: `shoulder${s}`, parent: 'body', pivot: [0.385 * side, 0.47, 0.02], drive: { rz: [['flap', 0.5 * side]] } },
9
+ {
10
+ name: `fore${s}`, parent: `shoulder${s}`, pivot: [0, -0.17, 0],
11
+ jiggle: { axis: [0, -1, 0], length: 0.16, freq: 3.2, damping: 0.35, maxAngle: 0.3 },
12
+ },
13
+ ];
14
+ }
15
+
16
+ function armParts(side: -1 | 1): PartSpec[] {
17
+ const s = side < 0 ? 'L' : 'R';
18
+ return [
19
+ { bone: `shoulder${s}`, shape: 'sphere', radius: 0.074, material: 'trim' },
20
+ { bone: `shoulder${s}`, shape: 'capsule', from: [0, -0.02, 0], to: [0, -0.15, 0], radius: 0.058, material: 'shell' },
21
+ { bone: `fore${s}`, shape: 'sphere', radius: 0.052, material: 'trim' },
22
+ { bone: `fore${s}`, shape: 'capsule', from: [0, -0.02, 0], to: [0, -0.12, 0], radius: 0.052, material: 'shell' },
23
+ /* a claw: a ball with a bite out of it */
24
+ { bone: `fore${s}`, shape: 'sphere', at: [0, -0.175, 0], radius: 0.066, material: 'trim' },
25
+ { bone: `fore${s}`, shape: 'sphere', op: 'sub', blend: 0.012, at: [0, -0.235, 0.012], radius: 0.036, material: 'trim' },
26
+ ];
27
+ }
28
+
29
+ /* knob ears that spin like gears when it thinks; two studs make the turn readable */
30
+ function earParts(side: -1 | 1): PartSpec[] {
31
+ const s = side < 0 ? 'L' : 'R';
32
+ return [
33
+ { bone: `ear${s}`, shape: 'cylinder', rot: [0, 0, 1.5708], radius: 0.112, half: 0.03, round: 0.018, material: 'trim' },
34
+ { bone: `ear${s}`, shape: 'cylinder', at: [0.045 * side, 0, 0], rot: [0, 0, 1.5708], radius: 0.058, half: 0.035, round: 0.018, material: 'trim' },
35
+ { bone: `ear${s}`, shape: 'sphere', at: [0.035 * side, 0.078, 0], radius: 0.02, material: 'metal' },
36
+ { bone: `ear${s}`, shape: 'sphere', at: [0.035 * side, -0.078, 0], radius: 0.02, material: 'metal' },
37
+ ];
38
+ }
39
+
40
+ /** A glossy TV-headed robot: LED face, jointed arms with claws, gear ears, sprung antenna. */
41
+ export const volt: CharacterSpec = {
42
+ id: 'volt',
43
+ name: 'Volt',
44
+ tagline: 'LED face, claw hands, gear ears, a sprung antenna',
45
+ accent: '#3b63d9',
46
+ frame: { target: 0.86, radius: 1.02 },
47
+ bound: { y: 0.86, radius: 1.12 },
48
+ motion: { hop: 0.16, squash: 1, snap: 1 },
49
+ glowPool: 0.35,
50
+ materials: {
51
+ shell: { color: '#2f56c4', f0: 0.05, spec: 0.7, shininess: 70, rim: 0.55, gloss: 0.55 },
52
+ trim: { color: '#c3cce3', f0: 0.07, spec: 0.8, shininess: 90, metal: 0.25, rim: 0.4, gloss: 0.5 },
53
+ metal: { color: '#8f98ae', f0: 0.45, spec: 1, shininess: 120, metal: 0.85, rim: 0.3, gloss: 0.7 },
54
+ rubber: { color: '#151a28', f0: 0.03, spec: 0.15, shininess: 12, rim: 0.2 },
55
+ screen: { color: '#03060c', f0: 0.045, spec: 1.6, shininess: 260, rim: 0.1, gloss: 1 },
56
+ bulb: { color: '#f2f5ff', f0: 0.04, spec: 0.6, shininess: 40, rim: 0.3, glows: true, emitStrength: 1.4, sss: 0.4, sssColor: '#ffffff' },
57
+ lamp: { color: '#e9eeff', f0: 0.05, spec: 1, shininess: 80, glows: true, emitStrength: 1.1, gloss: 0.9 },
58
+ ring: { color: '#d8e4ff', f0: 0.04, spec: 0.4, shininess: 30, glows: true, emitStrength: 1.6 },
59
+ },
60
+ bones: [
61
+ { name: 'body', pivot: [0, 0, 0], drive: { ry: [['yaw', 0.2]], rz: [['roll', 0.25]] } },
62
+ { name: 'head', parent: 'body', pivot: [0, 0.64, 0], drive: { rx: [['pitch', -1]], ry: [['yaw', 0.8]], rz: [['roll', 0.75]] } },
63
+ { name: 'antenna', parent: 'head', pivot: [0, 0.755, 0], jiggle: { axis: [0, 1, 0], length: 0.26, freq: 2.3, damping: 0.11 } },
64
+ { name: 'earL', parent: 'head', pivot: [-0.585, 0.37, 0] },
65
+ { name: 'earR', parent: 'head', pivot: [0.585, 0.37, 0] },
66
+ ...arm(-1),
67
+ ...arm(1),
68
+ ],
69
+ parts: [
70
+ /* the body: a soft puck on two feet, a lamp and a speaker grille in the chest */
71
+ { bone: 'body', shape: 'roundBox', at: [0, 0.32, 0], half: [0.35, 0.27, 0.28], round: 0.22, material: 'shell' },
72
+ { bone: 'body', shape: 'roundBox', at: [0, 0.38, 0.27], half: [0.15, 0.08, 0.03], round: 0.06, material: 'rubber' },
73
+ { bone: 'body', shape: 'sphere', at: [0, 0.38, 0.285], radius: 0.04, material: 'lamp' },
74
+ { bone: 'body', shape: 'plate', op: 'sub', blend: 0.006, at: [0, 0.225, 0.3], half: [0.075, 0.009], corner: 0.009, depth: 0.03, material: 'shell' },
75
+ { bone: 'body', shape: 'plate', op: 'sub', blend: 0.006, at: [0, 0.19, 0.295], half: [0.075, 0.009], corner: 0.009, depth: 0.03, material: 'shell' },
76
+ { bone: 'body', shape: 'plate', op: 'sub', blend: 0.006, at: [0, 0.155, 0.27], half: [0.06, 0.009], corner: 0.009, depth: 0.03, material: 'shell' },
77
+ { bone: 'body', shape: 'roundBox', at: [-0.17, 0.035, 0.05], half: [0.11, 0.035, 0.14], round: 0.035, material: 'trim' },
78
+ { bone: 'body', shape: 'roundBox', at: [0.17, 0.035, 0.05], half: [0.11, 0.035, 0.14], round: 0.035, material: 'trim' },
79
+ { bone: 'body', shape: 'cylinder', at: [0, 0.62, 0], radius: 0.075, half: 0.06, round: 0.02, material: 'metal' },
80
+
81
+ /* the head: a shell with a rolled lip into the screen, and the glass */
82
+ { bone: 'head', shape: 'roundBox', at: [0, 0.37, 0], half: [0.56, 0.37, 0.35], round: 0.17, material: 'shell' },
83
+ { bone: 'head', shape: 'roundBox', op: 'sub', blend: 0.035, at: [0, 0.37, 0.41], half: [0.45, 0.28, 0.1], round: 0.12, material: 'shell' },
84
+ { bone: 'head', shape: 'plate', at: [0, 0.37, 0.31], half: [0.45, 0.28], corner: 0.12, depth: 0.012, material: 'screen' },
85
+ /* glowing rings where the ears meet the head */
86
+ { bone: 'head', shape: 'cylinder', at: [-0.555, 0.37, 0], rot: [0, 0, 1.5708], radius: 0.122, half: 0.012, round: 0.006, material: 'ring' },
87
+ { bone: 'head', shape: 'cylinder', at: [0.555, 0.37, 0], rot: [0, 0, 1.5708], radius: 0.122, half: 0.012, round: 0.006, material: 'ring' },
88
+ ...earParts(-1),
89
+ ...earParts(1),
90
+ /* the antenna's collar, stem and bulb */
91
+ { bone: 'head', shape: 'cylinder', at: [0, 0.745, 0], radius: 0.065, half: 0.025, round: 0.012, material: 'trim' },
92
+ { bone: 'antenna', shape: 'capsule', from: [0, 0, 0], to: [0, 0.2, 0], radius: 0.016, material: 'metal' },
93
+ { bone: 'antenna', shape: 'sphere', at: [0, 0.25, 0], radius: 0.055, material: 'bulb' },
94
+
95
+ ...armParts(-1),
96
+ ...armParts(1),
97
+ ],
98
+ face: {
99
+ kind: 'screen',
100
+ bone: 'head',
101
+ material: 'screen',
102
+ center: [0, 0.37],
103
+ half: [0.44, 0.27],
104
+ corner: 0.11,
105
+ cell: 0.034,
106
+ color: '#c4ecff',
107
+ },
108
+ anchors: {
109
+ top: { bone: 'head', at: [0.3, 0.78, 0.1] },
110
+ mouth: { bone: 'head', at: [0, 0.22, 0.34] },
111
+ ear: { bone: 'head', at: [-0.66, 0.37, 0] },
112
+ feet: { bone: 'root', at: [0, 0.02, 0.06] },
113
+ antenna: { bone: 'antenna', at: [0, 0.25, 0] },
114
+ },
115
+ acting: {
116
+ idle: {
117
+ shoulderL: { rz: [-0.08, 0.04, 0.45, 0], rx: [0, 0.06, 0.35, 1] },
118
+ shoulderR: { rz: [0.08, 0.04, 0.45, 1.6], rx: [0, 0.06, 0.35, 2.4] },
119
+ foreL: { rx: -0.25 },
120
+ foreR: { rx: -0.25 },
121
+ },
122
+ /* the thinker: one claw up to the chin and tapping, the other arm across the belly */
123
+ thinking: {
124
+ shoulderR: { rx: -1.5, ry: -0.8, rz: -0.1 },
125
+ foreR: { rx: [-0.95, 0.1, 1.8, 0] },
126
+ shoulderL: { rx: -1.0, ry: 0.8, rz: -0.3 },
127
+ foreL: { rx: -0.8 },
128
+ earL: { rx: [0, 0, 0, 0, 5] },
129
+ earR: { rx: [0, 0, 0, 0, -5] },
130
+ },
131
+ /* a claw cupped up by the ear */
132
+ listening: {
133
+ shoulderL: { rx: 0.1, ry: 0.3, rz: -2.8 },
134
+ foreL: { rx: -0.6 },
135
+ shoulderR: { rz: 0.14, rx: 0.05 },
136
+ foreR: { rx: -0.3 },
137
+ earL: { rx: [0.3, 0.15, 0.8, 0] },
138
+ },
139
+ /* talking with its hands */
140
+ speaking: {
141
+ shoulderL: { rx: [-0.55, 0.32, 0.72, 0], rz: [-0.28, 0.12, 0.5, 0] },
142
+ foreL: { rx: [-0.85, 0.38, 1.44, 0.6] },
143
+ shoulderR: { rx: [-0.45, 0.32, 0.72, 2.2], rz: [0.28, 0.12, 0.5, 1] },
144
+ foreR: { rx: [-0.95, 0.38, 1.44, 2.8] },
145
+ earL: { rx: [0, 0, 0, 0, 1.4] },
146
+ earR: { rx: [0, 0, 0, 0, -1.4] },
147
+ },
148
+ sleeping: {
149
+ shoulderL: { rz: -0.03, rx: -0.3 },
150
+ shoulderR: { rz: 0.03, rx: -0.3 },
151
+ foreL: { rx: -0.4 },
152
+ foreR: { rx: -0.4 },
153
+ },
154
+ /* typing: arms forward, claws tapping in turn, ears turning like drives */
155
+ working: {
156
+ shoulderL: { rx: -0.85, rz: -0.12 },
157
+ shoulderR: { rx: -0.85, rz: 0.12 },
158
+ foreL: { rx: [-0.95, 0.2, 6, 0] },
159
+ foreR: { rx: [-0.95, 0.2, 6, Math.PI] },
160
+ earL: { rx: [0, 0, 0, 0, 3] },
161
+ earR: { rx: [0, 0, 0, 0, -3] },
162
+ },
163
+ /* arms thrown out, shaking; the ears seize up */
164
+ error: {
165
+ shoulderL: { rz: [-0.95, 0.1, 11, 0], rx: -0.2 },
166
+ shoulderR: { rz: [0.95, 0.1, 11, 1], rx: -0.2 },
167
+ foreL: { rx: -1.1 },
168
+ foreR: { rx: -1.1 },
169
+ },
170
+ surprised: {
171
+ shoulderL: { rz: -1.55, rx: -0.3 },
172
+ shoulderR: { rz: 1.55, rx: -0.3 },
173
+ foreL: { rx: -0.35 },
174
+ foreR: { rx: -0.35 },
175
+ },
176
+ /* fists pumping overhead, ears spinning */
177
+ celebrating: {
178
+ shoulderL: { rz: [-2.55, 0.28, 4, 0] },
179
+ shoulderR: { rz: [2.55, 0.28, 4, Math.PI] },
180
+ foreL: { rz: [0.2, 0.4, 8, 0] },
181
+ foreR: { rz: [-0.2, 0.4, 8, Math.PI] },
182
+ earL: { rx: [0, 0, 0, 0, 12] },
183
+ earR: { rx: [0, 0, 0, 0, -12] },
184
+ },
185
+ /* arms hanging, a little behind the body */
186
+ sad: {
187
+ shoulderL: { rz: 0.04, rx: 0.22 },
188
+ shoulderR: { rz: -0.04, rx: 0.22 },
189
+ foreL: { rx: -0.05 },
190
+ foreR: { rx: -0.05 },
191
+ },
192
+ /* both arms up, claws waving */
193
+ happy: {
194
+ shoulderL: { rz: [-2.5, 0.22, 2.2, 0] },
195
+ foreL: { rz: [0.1, 0.5, 4.2, 0] },
196
+ shoulderR: { rz: [2.5, 0.22, 2.2, 1.5] },
197
+ foreR: { rz: [-0.1, 0.5, 4.2, 2] },
198
+ earL: { rx: [0, 0, 0, 0, 10] },
199
+ earR: { rx: [0, 0, 0, 0, -10] },
200
+ },
201
+ },
202
+ fx: {
203
+ replace: ['syllable'],
204
+ /* sound comes out of the sides of the screen */
205
+ syllable: [{ glyph: 'arc', anchor: 'mouth', rate: 2, offset: [0.5, 0.1, -0.1], mirror: true, velocity: [0.26, 0.02, 0.02], jitter: 0.02, life: [0.55, 0.7], size: [0.04, 0.1], rotation: 0, color: '#6aaee6' }],
206
+ /* signal rings off the antenna while it thinks and listens */
207
+ thinking: [{ glyph: 'ring', anchor: 'antenna', rate: 1.3, velocity: [0, 0.02, 0], life: [0.9, 1.1], size: [0.03, 0.17], color: '#ffb347', glow: true }],
208
+ listening: [{ glyph: 'ring', anchor: 'antenna', rate: 1.1, velocity: [0, 0, 0], life: [1, 1.2], size: [0.2, 0.03], color: '#62e39a', glow: true }],
209
+ land: [{ glyph: 'spark', anchor: 'feet', rate: 6, spread: 0.12, velocity: [0, 0.6, 0], jitter: 1.1, gravity: 3, life: [0.25, 0.42], size: [0.035, 0.02], color: '#ffd27a', glow: true, align: true }],
210
+ 'enter:happy': [{ glyph: 'spark', anchor: 'antenna', rate: 8, velocity: [0, 0.5, 0], jitter: 1.4, gravity: 2, life: [0.3, 0.5], size: [0.04, 0.02], color: '#ffe08a', glow: true, align: true }],
211
+ },
212
+ };
213
+
214
+ export default volt;