wobnimo 0.1.3 → 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 (71) 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 +20 -2
  37. package/dist/element.js +11 -11
  38. package/dist/index-Cm5wWKoT.d.ts +12 -0
  39. package/dist/index.d.ts +7 -2
  40. package/dist/index.js +6 -6
  41. package/dist/{status-DVudJbtp.d.ts → mascot-DZ91_ss-.d.ts} +1 -10
  42. package/dist/react.d.ts +2 -1
  43. package/dist/react.js +16 -16
  44. package/dist/status-C14-19fT.d.ts +12 -0
  45. package/dist/wobnimo.js +15 -15
  46. package/package.json +30 -4
  47. package/skill/SKILL.md +719 -0
  48. package/skill/examples/bao.ts +73 -0
  49. package/skill/examples/berry.ts +97 -0
  50. package/skill/examples/boo.ts +87 -0
  51. package/skill/examples/bumble.ts +70 -0
  52. package/skill/examples/cacti.ts +79 -0
  53. package/skill/examples/cap.ts +59 -0
  54. package/skill/examples/drift.ts +74 -0
  55. package/skill/examples/ember.ts +78 -0
  56. package/skill/examples/hop.ts +66 -0
  57. package/skill/examples/inky.ts +168 -0
  58. package/skill/examples/latte.ts +73 -0
  59. package/skill/examples/microduck.ts +222 -0
  60. package/skill/examples/miso.ts +182 -0
  61. package/skill/examples/mochi.ts +78 -0
  62. package/skill/examples/pebble.ts +174 -0
  63. package/skill/examples/pip.ts +170 -0
  64. package/skill/examples/rex.ts +193 -0
  65. package/skill/examples/swirl.ts +69 -0
  66. package/skill/examples/tad.ts +117 -0
  67. package/skill/examples/volt.ts +214 -0
  68. package/skill/reference/recipes.md +551 -0
  69. package/skill/reference/spec.md +258 -0
  70. package/skill/templates/starter.ts +73 -0
  71. package/dist/element-DRDEWSGV.d.ts +0 -8
@@ -0,0 +1,73 @@
1
+ import type { CharacterSpec } from 'wobnimo';
2
+
3
+ /** A chubby panda. */
4
+ export const bao: CharacterSpec = {
5
+ id: 'bao',
6
+ name: 'Bao',
7
+ tagline: 'A chubby panda cub: round ears, eye patches, and a belly made for sitting',
8
+ accent: '#2f3b4c',
9
+ frame: { target: 0.46, radius: 0.62 },
10
+ bound: { y: 0.45, radius: 0.57 },
11
+ motion: { hop: 0.1, squash: 1.2, snap: 0.9, talkSquash: 0.4 },
12
+ materials: {
13
+ white: { color: '#f6f3ec', f0: 0.03, spec: 0.4, shininess: 20, rim: 1, sheen: 0.6, surface: { kind: 'fur', scale: 100, strength: 0.3, bone: 'head' } },
14
+ whiteBody: { color: '#f6f3ec', shadeOf: 'white', f0: 0.03, spec: 0.4, shininess: 20, rim: 1, sheen: 0.6, surface: { kind: 'fur', scale: 100, strength: 0.3 } },
15
+ black: { color: '#26252b', f0: 0.03, spec: 0.4, shininess: 20, rim: 0.9, sheen: 0.6, surface: { kind: 'fur', scale: 100, strength: 0.3 } },
16
+ nose: { color: '#1b1a1f', f0: 0.06, spec: 1.8, shininess: 200, rim: 0.3, gloss: 0.9 },
17
+ },
18
+ bones: [
19
+ { name: 'body', pivot: [0, 0, 0], drive: { ry: [['yaw', 0.2]], rz: [['roll', 0.35]] }, wave: { rz: [0.02, 0.5, 0] } },
20
+ { name: 'head', parent: 'body', pivot: [0, 0.48, 0.02], drive: { rx: [['pitch', -1]], ry: [['yaw', 0.8]], rz: [['roll', 0.7]] } },
21
+ { name: 'armL', parent: 'body', pivot: [-0.22, 0.38, 0.06], rest: { rz: -0.4 }, drive: { rz: [['flap', -1]] } },
22
+ { name: 'armR', parent: 'body', pivot: [0.22, 0.38, 0.06], rest: { rz: 0.4 }, drive: { rz: [['flap', 1]] } },
23
+ ],
24
+ parts: [
25
+ { bone: 'body', shape: 'ellipsoid', at: [0, 0.26, 0], radii: [0.29, 0.27, 0.26], material: 'whiteBody' },
26
+ /* sitting legs, black, out front */
27
+ { bone: 'body', shape: 'ellipsoid', at: [-0.15, 0.08, 0.14], radii: [0.1, 0.08, 0.12], blend: 0.05, material: 'black' },
28
+ { bone: 'body', shape: 'ellipsoid', at: [0.15, 0.08, 0.14], radii: [0.1, 0.08, 0.12], blend: 0.05, material: 'black' },
29
+ /* a black band over the shoulders */
30
+ { bone: 'body', shape: 'ellipsoid', at: [0, 0.42, -0.01], radii: [0.27, 0.07, 0.24], blend: 0.05, material: 'black' },
31
+ { bone: 'armL', shape: 'capsule', from: [0, 0, 0], to: [-0.04, -0.16, 0.06], radius: 0.07, blend: 0.04, material: 'black' },
32
+ { bone: 'armR', shape: 'capsule', from: [0, 0, 0], to: [0.04, -0.16, 0.06], radius: 0.07, blend: 0.04, material: 'black' },
33
+ /* a big round head and round ears */
34
+ { bone: 'head', shape: 'ellipsoid', at: [0, 0.14, 0], radii: [0.28, 0.24, 0.24], blend: 0.1, material: 'white' },
35
+ { bone: 'head', shape: 'ellipsoid', at: [0, 0.06, 0.18], radii: [0.1, 0.07, 0.08], blend: 0.06, material: 'white' },
36
+ { bone: 'head', shape: 'ellipsoid', at: [0, 0.09, 0.26], radii: [0.035, 0.022, 0.02], material: 'nose' },
37
+ { bone: 'head', shape: 'sphere', at: [-0.2, 0.33, -0.02], radius: 0.075, blend: 0.03, material: 'black' },
38
+ { bone: 'head', shape: 'sphere', at: [0.2, 0.33, -0.02], radius: 0.075, blend: 0.03, material: 'black' },
39
+ ],
40
+ paints: [
41
+ /* droopy eye patches */
42
+ { bone: 'head', on: ['white'], kind: 'ellipse', at: [-0.1, 0.15, 0.2], radii: [0.06, 0.08], color: '#26252b', soft: 0.2 },
43
+ { bone: 'head', on: ['white'], kind: 'ellipse', at: [0.1, 0.15, 0.2], radii: [0.06, 0.08], color: '#26252b', soft: 0.2 },
44
+ { bone: 'head', on: ['white'], kind: 'sphere', at: [-0.17, 0.05, 0.18], radius: 0.04, color: '#ffb3c1', soft: 0.6, opacity: 0.7 },
45
+ { bone: 'head', on: ['white'], kind: 'sphere', at: [0.17, 0.05, 0.18], radius: 0.04, color: '#ffb3c1', soft: 0.6, opacity: 0.7 },
46
+ ],
47
+ eyes: { kind: 'ball', bone: 'head', at: [[-0.095, 0.16, 0.21], [0.095, 0.16, 0.21]], radius: 0.04, iris: '#3a2a20', irisSize: 0.7, pupilSize: 0.5, lid: 'black' },
48
+ face: { kind: 'mouth', bone: 'head', on: ['white'], at: [0, 0.035, 0.25], width: 0.04, color: '#26252b', tongue: '#ff8fa3' },
49
+ anchors: {
50
+ top: { bone: 'head', at: [0.15, 0.45, 0.05] },
51
+ mouth: { bone: 'head', at: [0, 0.035, 0.27] },
52
+ ear: { bone: 'head', at: [-0.22, 0.33, 0] },
53
+ feet: { bone: 'root', at: [0, 0.02, 0.18] },
54
+ },
55
+ acting: {
56
+ idle: { armL: { rz: [0, 0.05, 0.5, 0] } },
57
+ thinking: { armR: { rz: 1.5, rx: -1.2, ry: -0.4 }, head: { rz: 0.1 } },
58
+ listening: { armL: { rz: -0.6, rx: -0.4 } },
59
+ speaking: { armL: { rz: [-0.2, 0.2, 1.2, 0] }, armR: { rz: [0.2, 0.2, 1.2, 1.4] } },
60
+ sleeping: { head: { rx: 0.25, rz: 0.15 } },
61
+ working: { armL: { rx: [-0.8, 0.2, 5, 0] }, armR: { rx: [-0.8, 0.2, 5, Math.PI] } },
62
+ error: { armL: { rz: -1.6, rx: -0.6 }, armR: { rz: 1.6, rx: -0.6 } },
63
+ surprised: { armL: { rz: -1.1 }, armR: { rz: 1.1 } },
64
+ celebrating: { armL: { rz: [-2.2, 0.3, 4, 0] }, armR: { rz: [2.2, 0.3, 4, Math.PI] } },
65
+ sad: { head: { rx: 0.3 }, armL: { rz: 0.1 }, armR: { rz: -0.1 } },
66
+ happy: { armL: { rz: [-1.5, 0.3, 3, 0] }, armR: { rz: [1.5, 0.3, 3, 1] } },
67
+ },
68
+ fx: {
69
+ happy: [{ glyph: 'heart', anchor: 'top', rate: 1.2, velocity: [0, 0.22, 0.04], jitter: 0.1, life: [1, 1.3], size: [0.04, 0.06], color: '#ff86b0' }],
70
+ },
71
+ };
72
+
73
+ export default bao;
@@ -0,0 +1,97 @@
1
+ import type { CharacterSpec, PaintSpec, PartSpec } from 'wobnimo';
2
+
3
+ /** A strawberry with a leafy hat. */
4
+ export const berry: CharacterSpec = {
5
+ id: 'berry',
6
+ name: 'Berry',
7
+ tagline: 'A plump strawberry with golden seeds and a leafy hat with a stalk on top',
8
+ accent: '#e8324f',
9
+ frame: { target: 0.43, radius: 0.57 },
10
+ bound: { y: 0.41, radius: 0.5 },
11
+ motion: { hop: 0.15, squash: 1.3, snap: 1.1, talkSquash: 0.5 },
12
+ materials: {
13
+ berry: { color: '#e8324f', f0: 0.07, spec: 1.6, shininess: 130, rim: 0.6, sss: 0.35, sssColor: '#ff7d8f', gloss: 0.8 },
14
+ leaf: { color: '#3fa34d', f0: 0.04, spec: 0.7, shininess: 50, rim: 0.6, sss: 0.25, sssColor: '#b8f0a0' },
15
+ bead: { color: '#1a1012', f0: 0.06, spec: 2.2, shininess: 400, rim: 0.2, gloss: 1 },
16
+ },
17
+ bones: [
18
+ { name: 'body', pivot: [0, -0.042, 0], drive: { rx: [['pitch', -0.4]], ry: [['yaw', 0.6]], rz: [['roll', 0.5]] } },
19
+ { name: 'hat', parent: 'body', pivot: [0, 0.73, 0], jiggle: { axis: [0, 1, 0], length: 0.12, freq: 3.2, damping: 0.16, maxAngle: 0.5 } },
20
+ ],
21
+ parts: [
22
+ /* a rounded heart-shaped berry: wide at the shoulders, a soft point at the bottom */
23
+ { bone: 'body', shape: 'roundCone', from: [0, 0.2, 0], to: [0, 0.48, 0], r1: 0.17, r2: 0.3, material: 'berry' },
24
+ { bone: 'body', shape: 'ellipsoid', at: [0, 0.5, 0], radii: [0.3, 0.2, 0.28], blend: 0.08, material: 'berry' },
25
+ /* five leaves splayed over the shoulders, and a stalk */
26
+ ...[0, 1, 2, 3, 4].map((i): PartSpec => {
27
+ const a = (i / 5) * Math.PI * 2 + 0.3;
28
+ return { bone: 'hat', shape: 'ellipsoid', at: [Math.sin(a) * 0.15, -0.005, Math.cos(a) * 0.15], rot: [0.5, a, 0], radii: [0.075, 0.024, 0.15], blend: 0.02, material: 'leaf' };
29
+ }),
30
+ { bone: 'hat', shape: 'capsule', from: [0, 0, 0], to: [0.02, 0.1, 0], radius: 0.022, blend: 0.03, material: 'leaf' },
31
+ ],
32
+ paints: [
33
+ /* golden seeds spiralled evenly over the skin, skipping the face; each sits exactly on the surface */
34
+ ...([
35
+ [0, 0.2, 0.192],
36
+ [0.133, 0.21, -0.145],
37
+ [-0.202, 0.22, 0.018],
38
+ [0.165, 0.229, 0.126],
39
+ [-0.037, 0.239, -0.209],
40
+ [-0.117, 0.249, 0.184],
41
+ [0.215, 0.259, -0.058],
42
+ [-0.202, 0.268, -0.105],
43
+ [0.08, 0.278, 0.219],
44
+ [0.091, 0.288, -0.22],
45
+ [-0.221, 0.298, 0.103],
46
+ [0.238, 0.308, 0.075],
47
+ [-0.128, 0.317, -0.22],
48
+ [-0.056, 0.327, 0.254],
49
+ [0.218, 0.337, -0.154],
50
+ [-0.272, 0.347, -0.035],
51
+ [0.012, 0.366, -0.281],
52
+ [-0.203, 0.376, 0.204],
53
+ [0.294, 0.386, -0.014],
54
+ [-0.227, 0.396, -0.19],
55
+ [0.172, 0.415, -0.248],
56
+ [-0.301, 0.425, 0.068],
57
+ [0.269, 0.435, 0.154],
58
+ [-0.093, 0.444, -0.293],
59
+ [0.292, 0.464, -0.122],
60
+ [-0.299, 0.474, -0.108],
61
+ [0.079, 0.493, -0.301],
62
+ [-0.266, 0.503, 0.171],
63
+ [0.314, 0.513, 0.054],
64
+ [-0.191, 0.523, -0.247],
65
+ [0.227, 0.542, -0.21],
66
+ [-0.312, 0.552, 0.001],
67
+ [0.225, 0.562, 0.205],
68
+ [-0.027, 0.572, -0.296],
69
+ [0.291, 0.591, -0.053],
70
+ [-0.245, 0.601, -0.154],
71
+ [0.074, 0.611, 0.27],
72
+ [0.126, 0.62, -0.245],
73
+ [-0.256, 0.63, 0.095],
74
+ [0.246, 0.64, 0.1]
75
+ ] as const).map(([x, y, z]): PaintSpec => ({ bone: 'body', on: ['berry'], kind: 'sphere', at: [x, y, z], radius: 0.022, color: '#ffd166', soft: 0.2 })),
76
+ { bone: 'body', on: ['berry'], kind: 'sphere', at: [-0.16, 0.42, 0.25], radius: 0.05, color: '#ff9ab0', soft: 0.6, opacity: 0.6 },
77
+ { bone: 'body', on: ['berry'], kind: 'sphere', at: [0.16, 0.42, 0.25], radius: 0.05, color: '#ff9ab0', soft: 0.6, opacity: 0.6 },
78
+ ],
79
+ eyes: { kind: 'bead', bone: 'body', at: [[-0.09, 0.5, 0.3], [0.09, 0.5, 0.3]], radii: [0.03, 0.045, 0.02], material: 'bead' },
80
+ face: { kind: 'mouth', bone: 'body', on: ['berry'], at: [0, 0.41, 0.3], width: 0.045, color: '#5a1020', tongue: '#ff8fa3' },
81
+ anchors: {
82
+ top: { bone: 'hat', at: [0.06, 0.16, 0] },
83
+ mouth: { bone: 'body', at: [0, 0.41, 0.31] },
84
+ ear: { bone: 'body', at: [-0.3, 0.5, 0] },
85
+ feet: { bone: 'root', at: [0, 0.02, 0.12] },
86
+ },
87
+ acting: {
88
+ thinking: { hat: { rz: 0.3 } },
89
+ sleeping: { hat: { rz: 0.4, rx: 0.2 } },
90
+ error: { hat: { rz: [0, 0.3, 9, 0] } },
91
+ celebrating: { hat: { ry: [0, 0, 0, 0, 10] } },
92
+ sad: { hat: { rx: 0.4, rz: 0.3 } },
93
+ happy: { hat: { ry: [0, 0, 0, 0, 14] } },
94
+ },
95
+ };
96
+
97
+ export default berry;
@@ -0,0 +1,87 @@
1
+ import type { CharacterSpec } from 'wobnimo';
2
+
3
+ /** A floating ghost with a rippling hem and little arms. */
4
+ export const boo: CharacterSpec = {
5
+ id: 'boo',
6
+ name: 'Boo',
7
+ tagline: 'Floats, glows from inside, trails motes, a hem that ripples',
8
+ accent: '#8a6cf0',
9
+ frame: { target: 0.78, radius: 0.92 },
10
+ bound: { y: 0.72, radius: 0.72 },
11
+ motion: { float: 0.22, hop: 0.12, squash: 0.8, snap: 0.8, talkSquash: 0.6 },
12
+ glowPool: 0.55,
13
+ materials: {
14
+ ghost: { color: '#eceaff', f0: 0.04, spec: 0.5, shininess: 30, rim: 1.4, sss: 0.4, sssColor: '#b9a4ff', emit: '#6f52d9', emitStrength: 0.06 },
15
+ bead: { color: '#1b1430', f0: 0.06, spec: 2.2, shininess: 400, rim: 0.2, gloss: 1 },
16
+ },
17
+ bones: [
18
+ { name: 'body', pivot: [0, 0, 0], drive: { rx: [['pitch', -0.5]], ry: [['yaw', 0.7]], rz: [['roll', 0.6]] }, wave: { rz: [0.03, 0.45, 0] } },
19
+ {
20
+ name: 'armL', parent: 'body', pivot: [-0.36, 0.74, 0.04],
21
+ drive: { rz: [['flap', -1.2]] }, wave: { rz: [0.08, 0.7, 0] },
22
+ jiggle: { axis: [-0.8, -0.6, 0], length: 0.15, freq: 2, damping: 0.2, maxAngle: 0.7 },
23
+ },
24
+ {
25
+ name: 'armR', parent: 'body', pivot: [0.36, 0.74, 0.04],
26
+ drive: { rz: [['flap', 1.2]] }, wave: { rz: [-0.08, 0.7, 1.6] },
27
+ jiggle: { axis: [0.8, -0.6, 0], length: 0.15, freq: 2, damping: 0.2, maxAngle: 0.7 },
28
+ },
29
+ ],
30
+ parts: [
31
+ { bone: 'body', shape: 'sphere', at: [0, 0.88, 0], radius: 0.4, material: 'ghost' },
32
+ { bone: 'body', shape: 'roundCone', from: [0, 0.88, 0], to: [0, 0.4, 0], r1: 0.4, r2: 0.47, material: 'ghost' },
33
+ { bone: 'body', shape: 'hem', y: 0.34, amplitude: 0.045, waves: 6, speed: 2.4, blend: 0.05, material: 'ghost' },
34
+ { bone: 'armL', shape: 'capsule', from: [0, 0, 0], to: [-0.12, -0.09, 0.02], radius: 0.07, blend: 0.08, material: 'ghost' },
35
+ { bone: 'armR', shape: 'capsule', from: [0, 0, 0], to: [0.12, -0.09, 0.02], radius: 0.07, blend: 0.08, material: 'ghost' },
36
+ ],
37
+ paints: [
38
+ { bone: 'body', on: ['ghost'], kind: 'sphere', at: [-0.24, 0.78, 0.31], radius: 0.07, color: '#ffa3c4', soft: 0.6, opacity: 0.7 },
39
+ { bone: 'body', on: ['ghost'], kind: 'sphere', at: [0.24, 0.78, 0.31], radius: 0.07, color: '#ffa3c4', soft: 0.6, opacity: 0.7 },
40
+ ],
41
+ eyes: {
42
+ kind: 'bead',
43
+ bone: 'body',
44
+ at: [[-0.135, 0.9, 0.375], [0.135, 0.9, 0.375]],
45
+ radii: [0.048, 0.072, 0.03],
46
+ material: 'bead',
47
+ },
48
+ face: {
49
+ kind: 'mouth',
50
+ bone: 'body',
51
+ on: ['ghost'],
52
+ at: [0, 0.77, 0.38],
53
+ width: 0.075,
54
+ color: '#2a1a4a',
55
+ tongue: '#ff7fa6',
56
+ },
57
+ anchors: {
58
+ top: { bone: 'body', at: [0.16, 1.2, 0.1] },
59
+ mouth: { bone: 'body', at: [0, 0.77, 0.4] },
60
+ ear: { bone: 'body', at: [-0.42, 0.92, 0] },
61
+ center: { bone: 'body', at: [0, 0.8, 0] },
62
+ },
63
+ acting: {
64
+ idle: { armL: { rz: [0, 0.1, 0.7, 0] }, armR: { rz: [0, 0.1, 0.7, 1.3] } },
65
+ thinking: { armR: { ry: -1.1, rz: 0.9 }, armL: { rz: 0.25 } },
66
+ listening: { armL: { rz: -1, rx: -0.35 } },
67
+ speaking: {
68
+ armL: { rz: [-0.3, 0.3, 1.2, 0], rx: [-0.3, 0.2, 0.9, 0] },
69
+ armR: { rz: [0.3, 0.3, 1.2, 1.7], rx: [-0.3, 0.2, 0.9, 2.2] },
70
+ },
71
+ sleeping: { armL: { rz: 0.4 }, armR: { rz: -0.4 }, body: { rz: 0.08 } },
72
+ working: { armL: { rx: [-0.6, 0.15, 6, 0], rz: -0.3 }, armR: { rx: [-0.6, 0.15, 6, Math.PI], rz: 0.3 } },
73
+ error: { armL: { rz: [-1.0, 0.25, 10, 0] }, armR: { rz: [1.0, 0.25, 10, 1] } },
74
+ /* hands to its cheeks */
75
+ surprised: { armL: { rz: -1.4, rx: -0.4 }, armR: { rz: 1.4, rx: -0.4 } },
76
+ celebrating: { armL: { rz: [-1.6, 0.3, 4, 0] }, armR: { rz: [1.6, 0.3, 4, Math.PI] } },
77
+ sad: { armL: { rz: 0.5 }, armR: { rz: -0.5 }, body: { rz: 0.05 } },
78
+ happy: { armL: { rz: [-1.3, 0.35, 3, 0] }, armR: { rz: [1.3, 0.35, 3, 1.2] } },
79
+ },
80
+ fx: {
81
+ /* glowing motes drift around it all the time */
82
+ ambient: [{ glyph: 'mote', anchor: 'center', rate: 1.3, spread: 0.5, velocity: [0, 0.07, 0], jitter: 0.06, wobble: 0.09, life: [2.2, 3.2], size: [0.04, 0.02], color: '#b49cff', glow: true }],
83
+ happy: [{ glyph: 'heart', anchor: 'top', rate: 1.2, spread: 0.2, velocity: [0, 0.22, 0.05], jitter: 0.12, wobble: 0.06, life: [1, 1.3], size: [0.04, 0.07], color: '#ff86b0' }],
84
+ },
85
+ };
86
+
87
+ export default boo;
@@ -0,0 +1,70 @@
1
+ import type { CharacterSpec } from 'wobnimo';
2
+
3
+ /** A round bumblebee with tiny wings. */
4
+ export const bumble: CharacterSpec = {
5
+ id: 'bumble',
6
+ name: 'Bumble',
7
+ tagline: 'A fuzzy round bumblebee that hovers on wings far too small for it',
8
+ accent: '#f5b700',
9
+ frame: { target: 0.61, radius: 0.81 },
10
+ bound: { y: 0.5, radius: 0.62 },
11
+ motion: { float: 0.2, hop: 0.08, squash: 1, snap: 1.2, talkSquash: 0.5 },
12
+ materials: {
13
+ fuzz: {
14
+ color: '#ffc21a', f0: 0.03, spec: 0.4, shininess: 20, rim: 1.1, sheen: 0.8,
15
+ surface: { kind: 'fur', scale: 110, strength: 0.4, bone: 'body' },
16
+ },
17
+ stripe: { color: '#2b2118', f0: 0.03, spec: 0.4, shininess: 20, rim: 0.8, sheen: 0.6 },
18
+ wing: { color: '#e8f6ff', f0: 0.1, spec: 1.8, shininess: 200, rim: 1.4, sss: 0.6, sssColor: '#ffffff', gloss: 0.9 },
19
+ feeler: { color: '#2b2118', f0: 0.04, spec: 0.8, shininess: 60, rim: 0.5 },
20
+ },
21
+ bones: [
22
+ { name: 'body', pivot: [0, 0.4, 0], drive: { rx: [['pitch', -0.4]], ry: [['yaw', 0.7]], rz: [['roll', 0.6]] }, wave: { rx: [0.03, 0.8, 0] } },
23
+ /* wings buzz all the time */
24
+ { name: 'wingL', parent: 'body', pivot: [-0.12, 0.3, -0.18], rest: { rz: 0.5, rx: -0.3 }, wave: { rz: [0.35, 14, 0] } },
25
+ { name: 'wingR', parent: 'body', pivot: [0.12, 0.3, -0.18], rest: { rz: -0.5, rx: -0.3 }, wave: { rz: [-0.35, 14, 0] } },
26
+ { name: 'feelerL', parent: 'body', pivot: [-0.08, 0.36, 0.1], rest: { rz: 0.35 }, jiggle: { axis: [0, 1, 0], length: 0.14, freq: 3, damping: 0.12 } },
27
+ { name: 'feelerR', parent: 'body', pivot: [0.08, 0.36, 0.1], rest: { rz: -0.35 }, jiggle: { axis: [0, 1, 0], length: 0.14, freq: 3, damping: 0.12 } },
28
+ ],
29
+ parts: [
30
+ { bone: 'body', shape: 'sphere', at: [0, 0, 0], radius: 0.36, material: 'fuzz' },
31
+ /* a little stinger at the back */
32
+ { bone: 'body', shape: 'roundCone', from: [0, -0.05, -0.33], to: [0, -0.08, -0.45], r1: 0.05, r2: 0.01, blend: 0.03, material: 'stripe' },
33
+ { bone: 'wingL', shape: 'ellipsoid', at: [-0.1, 0.1, 0], rot: [0, 0, 0.5], radii: [0.12, 0.17, 0.012], material: 'wing' },
34
+ { bone: 'wingR', shape: 'ellipsoid', at: [0.1, 0.1, 0], rot: [0, 0, -0.5], radii: [0.12, 0.17, 0.012], material: 'wing' },
35
+ { bone: 'feelerL', shape: 'capsule', from: [0, 0, 0], to: [0, 0.14, 0.02], radius: 0.012, material: 'feeler' },
36
+ { bone: 'feelerL', shape: 'sphere', at: [0, 0.15, 0.02], radius: 0.03, material: 'feeler' },
37
+ { bone: 'feelerR', shape: 'capsule', from: [0, 0, 0], to: [0, 0.14, 0.02], radius: 0.012, material: 'feeler' },
38
+ { bone: 'feelerR', shape: 'sphere', at: [0, 0.15, 0.02], radius: 0.03, material: 'feeler' },
39
+ ],
40
+ paints: [
41
+ /* two dark bands around the lower body, made from big soft-edged spheres below it */
42
+ { bone: 'body', on: ['fuzz'], kind: 'sphere', at: [0, -1.04, 0], radius: 0.9, color: '#2b2118', soft: 0.03 },
43
+ { bone: 'body', on: ['fuzz'], kind: 'sphere', at: [0, -1.15, 0], radius: 0.9, color: '#ffc21a', soft: 0.03 },
44
+ { bone: 'body', on: ['fuzz'], kind: 'sphere', at: [0, -1.25, 0], radius: 0.9, color: '#2b2118', soft: 0.03 },
45
+ { bone: 'body', on: ['fuzz'], kind: 'sphere', at: [0, 0.98, 0], radius: 0.7, color: '#2b2118', soft: 0.04 },
46
+ { bone: 'body', on: ['fuzz'], kind: 'sphere', at: [-0.2, -0.05, 0.27], radius: 0.06, color: '#ff8a6a', soft: 0.6, opacity: 0.7 },
47
+ { bone: 'body', on: ['fuzz'], kind: 'sphere', at: [0.2, -0.05, 0.27], radius: 0.06, color: '#ff8a6a', soft: 0.6, opacity: 0.7 },
48
+ ],
49
+ eyes: { kind: 'ball', bone: 'body', at: [[-0.12, 0.06, 0.3], [0.12, 0.06, 0.3]], radius: 0.065, iris: '#20160e', irisSize: 0.85, pupilSize: 0.55, lid: 'fuzz' },
50
+ face: { kind: 'mouth', bone: 'body', on: ['fuzz'], at: [0, -0.08, 0.35], width: 0.05, color: '#3a2412', tongue: '#ff7d6e' },
51
+ anchors: {
52
+ top: { bone: 'body', at: [0.12, 0.5, 0.05] },
53
+ mouth: { bone: 'body', at: [0, -0.08, 0.37] },
54
+ ear: { bone: 'body', at: [-0.36, 0.05, 0] },
55
+ center: { bone: 'body', at: [0, 0, 0] },
56
+ },
57
+ acting: {
58
+ thinking: { feelerL: { rz: 0.6 }, feelerR: { rz: -0.1 } },
59
+ listening: { feelerL: { rx: -0.4 }, feelerR: { rx: -0.4 } },
60
+ sleeping: { wingL: { rz: 0.9 }, wingR: { rz: -0.9 }, feelerL: { rx: 0.6 }, feelerR: { rx: 0.6 } },
61
+ error: { feelerL: { rz: [0.4, 0.3, 9, 0] }, feelerR: { rz: [-0.4, 0.3, 9, 1] } },
62
+ surprised: { feelerL: { rz: 0.1, rx: -0.3 }, feelerR: { rz: -0.1, rx: -0.3 } },
63
+ sad: { feelerL: { rx: 0.9 }, feelerR: { rx: 0.9 } },
64
+ },
65
+ fx: {
66
+ happy: [{ glyph: 'sparkle', anchor: 'top', rate: 2, velocity: [0, 0.2, 0.05], jitter: 0.15, life: [0.8, 1.1], size: [0.04, 0.02], color: '#ffd84d', glow: true }],
67
+ },
68
+ };
69
+
70
+ export default bumble;
@@ -0,0 +1,79 @@
1
+ import type { CharacterSpec, PartSpec } from 'wobnimo';
2
+
3
+ /** A tiny potted cactus with a pink flower on its head. */
4
+ export const cacti: CharacterSpec = {
5
+ id: 'cacti',
6
+ name: 'Cacti',
7
+ tagline: 'A tiny potted cactus with a pink flower that bounces on its head',
8
+ accent: '#3fae6a',
9
+ frame: { target: 0.52, radius: 0.69 },
10
+ bound: { y: 0.52, radius: 0.61 },
11
+ motion: { hop: 0.08, squash: 0.9, snap: 1, talkSquash: 0.5 },
12
+ materials: {
13
+ cactus: {
14
+ color: '#4cb873', f0: 0.04, spec: 0.8, shininess: 60, rim: 0.8, sss: 0.2, sssColor: '#a8f0b0', gloss: 0.4,
15
+ surface: { kind: 'speckle', scale: 30, strength: 0.4, color: '#2f8a52', bone: 'body' },
16
+ },
17
+ pot: { color: '#d9774a', f0: 0.03, spec: 0.4, shininess: 25, rim: 0.4 },
18
+ rim: { color: '#e88a5c', shadeOf: 'pot', f0: 0.03, spec: 0.4, shininess: 25, rim: 0.4 },
19
+ soil: { color: '#5b3a28', f0: 0.02, spec: 0.1, shininess: 8, rim: 0.2 },
20
+ petal: { color: '#ff7eb6', f0: 0.04, spec: 0.6, shininess: 40, rim: 0.7, sss: 0.4, sssColor: '#ffc1dc', sheen: 0.4 },
21
+ pollen: { color: '#ffd84d', f0: 0.04, spec: 0.5, shininess: 30, rim: 0.4 },
22
+ bead: { color: '#141a14', f0: 0.06, spec: 2.2, shininess: 400, rim: 0.2, gloss: 1 },
23
+ },
24
+ bones: [
25
+ { name: 'body', pivot: [0, 0.32, 0], drive: { rx: [['pitch', -0.3]], ry: [['yaw', 0.5]], rz: [['roll', 0.5]] }, wave: { rz: [0.025, 0.5, 0] } },
26
+ { name: 'armL', parent: 'body', pivot: [-0.2, 0.25, 0], rest: { rz: 0.3 }, drive: { rz: [['flap', -0.8]] } },
27
+ { name: 'armR', parent: 'body', pivot: [0.2, 0.18, 0], rest: { rz: -0.2 }, drive: { rz: [['flap', 0.8]] } },
28
+ { name: 'flower', parent: 'body', pivot: [0.04, 0.56, 0], jiggle: { axis: [0, 1, 0], length: 0.1, freq: 3, damping: 0.14 } },
29
+ ],
30
+ parts: [
31
+ /* a terracotta pot with a fat rim */
32
+ { bone: 'root', shape: 'roundCone', from: [0, 0.03, 0], to: [0, 0.27, 0], r1: 0.2, r2: 0.25, clip: { normal: [0, -1, 0] }, material: 'pot' },
33
+ { bone: 'root', shape: 'cylinder', at: [0, 0.3, 0], radius: 0.28, half: 0.05, round: 0.03, material: 'rim' },
34
+ { bone: 'root', shape: 'cylinder', at: [0, 0.33, 0], radius: 0.24, half: 0.025, round: 0.01, material: 'soil' },
35
+ /* the cactus: a tall rounded body */
36
+ { bone: 'body', shape: 'capsule', from: [0, 0.05, 0], to: [0, 0.38, 0], radius: 0.2, material: 'cactus' },
37
+ /* little arms */
38
+ { bone: 'armL', shape: 'capsule', from: [0, 0, 0], to: [-0.1, 0, 0], radius: 0.065, blend: 0.04, material: 'cactus' },
39
+ { bone: 'armL', shape: 'capsule', from: [-0.1, 0, 0], to: [-0.11, 0.12, 0], radius: 0.06, blend: 0.03, material: 'cactus' },
40
+ { bone: 'armR', shape: 'capsule', from: [0, 0, 0], to: [0.1, 0, 0], radius: 0.06, blend: 0.04, material: 'cactus' },
41
+ { bone: 'armR', shape: 'capsule', from: [0.1, 0, 0], to: [0.11, 0.1, 0], radius: 0.055, blend: 0.03, material: 'cactus' },
42
+ /* a five-petal flower */
43
+ ...[0, 1, 2, 3, 4].map((i): PartSpec => {
44
+ const a = (i / 5) * Math.PI * 2;
45
+ return { bone: 'flower', shape: 'ellipsoid', at: [Math.cos(a) * 0.055, 0.03, Math.sin(a) * 0.055], rot: [0, -a, 0.4], radii: [0.055, 0.02, 0.035], blend: 0.01, material: 'petal' };
46
+ }),
47
+ { bone: 'flower', shape: 'sphere', at: [0, 0.045, 0], radius: 0.03, material: 'pollen' },
48
+ ],
49
+ paints: [
50
+ { bone: 'body', on: ['cactus'], kind: 'sphere', at: [-0.13, 0.2, 0.16], radius: 0.045, color: '#ff8fb4', soft: 0.6, opacity: 0.7 },
51
+ { bone: 'body', on: ['cactus'], kind: 'sphere', at: [0.13, 0.2, 0.16], radius: 0.045, color: '#ff8fb4', soft: 0.6, opacity: 0.7 },
52
+ ],
53
+ eyes: { kind: 'bead', bone: 'body', at: [[-0.08, 0.27, 0.185], [0.08, 0.27, 0.185]], radii: [0.03, 0.045, 0.02], material: 'bead' },
54
+ face: { kind: 'mouth', bone: 'body', on: ['cactus'], at: [0, 0.19, 0.2], width: 0.045, color: '#173a24', tongue: '#ff7d97' },
55
+ anchors: {
56
+ top: { bone: 'flower', at: [0, 0.1, 0] },
57
+ mouth: { bone: 'body', at: [0, 0.19, 0.22] },
58
+ ear: { bone: 'body', at: [-0.22, 0.3, 0] },
59
+ feet: { bone: 'root', at: [0, 0.02, 0.15] },
60
+ },
61
+ acting: {
62
+ idle: { armL: { rz: [0, 0.08, 0.6, 0] } },
63
+ thinking: { armR: { rz: 0.9, rx: -0.5 }, flower: { rz: 0.2 } },
64
+ listening: { armL: { rz: -0.4 }, flower: { rz: -0.15 } },
65
+ speaking: { armL: { rz: [-0.2, 0.25, 1.4, 0] }, armR: { rz: [0.2, 0.25, 1.4, 1.5] } },
66
+ sleeping: { flower: { rz: 0.6, rx: 0.4 }, body: { rz: 0.08 } },
67
+ working: { armL: { rz: [-0.4, 0.2, 5, 0] }, armR: { rz: [0.4, 0.2, 5, Math.PI] } },
68
+ error: { armL: { rz: -1 }, armR: { rz: 1 }, flower: { rz: [0, 0.3, 10, 0] } },
69
+ surprised: { armL: { rz: -0.9 }, armR: { rz: 0.9 } },
70
+ celebrating: { armL: { rz: [-0.9, 0.3, 4, 0] }, armR: { rz: [0.9, 0.3, 4, Math.PI] }, flower: { ry: [0, 0, 0, 0, 10] } },
71
+ sad: { flower: { rx: 0.9, rz: 0.4 }, armL: { rz: 0.4 }, armR: { rz: -0.3 } },
72
+ happy: { flower: { ry: [0, 0, 0, 0, 12] } },
73
+ },
74
+ fx: {
75
+ happy: [{ glyph: 'heart', anchor: 'top', rate: 1.2, velocity: [0, 0.22, 0.04], jitter: 0.1, life: [1, 1.3], size: [0.04, 0.06], color: '#ff7eb6' }],
76
+ },
77
+ };
78
+
79
+ export default cacti;
@@ -0,0 +1,59 @@
1
+ import type { CharacterSpec, PaintSpec } from 'wobnimo';
2
+
3
+ /** A red mushroom with white spots. */
4
+ export const cap: CharacterSpec = {
5
+ id: 'cap',
6
+ name: 'Cap',
7
+ tagline: 'A little toadstool with a glossy red cap that wobbles when it walks',
8
+ accent: '#e0393e',
9
+ frame: { target: 0.4, radius: 0.59 },
10
+ bound: { y: 0.39, radius: 0.5 },
11
+ motion: { hop: 0.12, squash: 1.2, snap: 1, talkSquash: 0.5 },
12
+ materials: {
13
+ cap: { color: '#e53935', f0: 0.06, spec: 1.5, shininess: 120, rim: 0.6, gloss: 0.75, sss: 0.15, sssColor: '#ff8a80' },
14
+ gills: { color: '#efe2cf', f0: 0.02, spec: 0.2, shininess: 10, rim: 0.3 },
15
+ stem: { color: '#fbf3e4', f0: 0.03, spec: 0.5, shininess: 30, rim: 0.6, sss: 0.3, sssColor: '#fff8ec' },
16
+ bead: { color: '#1a1414', f0: 0.06, spec: 2.2, shininess: 400, rim: 0.2, gloss: 1 },
17
+ },
18
+ bones: [
19
+ { name: 'body', pivot: [0, 0, 0], drive: { rx: [['pitch', -0.3]], ry: [['yaw', 0.5]], rz: [['roll', 0.4]] } },
20
+ { name: 'cap', parent: 'body', pivot: [0, 0.42, 0], drive: { rx: [['pitch', -0.4]], rz: [['roll', 0.5]] }, jiggle: { axis: [0, 1, 0], length: 0.2, freq: 2.6, damping: 0.18, maxAngle: 0.3 } },
21
+ ],
22
+ parts: [
23
+ /* a chubby stem the face lives on */
24
+ { bone: 'body', shape: 'roundCone', from: [0, 0.12, 0], to: [0, 0.4, 0], r1: 0.2, r2: 0.16, clip: { normal: [0, -1, 0] }, material: 'stem' },
25
+ /* a dome cap with a soft underside */
26
+ { bone: 'cap', shape: 'ellipsoid', at: [0, 0.06, 0], radii: [0.42, 0.28, 0.42], clip: { normal: [0, -1, 0], offset: 0.02 }, material: 'cap' },
27
+ { bone: 'cap', shape: 'ellipsoid', at: [0, 0.05, 0], radii: [0.4, 0.04, 0.4], blend: 0.03, material: 'gills' },
28
+ ],
29
+ paints: [
30
+ /* white spots, scattered over the cap */
31
+ ...([[0, 0.33, 0.05, 0.08], [-0.22, 0.24, 0.2, 0.07], [0.24, 0.22, 0.2, 0.065], [-0.08, 0.2, 0.33, 0.055], [0.12, 0.3, -0.18, 0.07], [-0.341, 0.196, -0.136, 0.06], [0.38, 0.173, -0.058, 0.05]] as const).map(
32
+ ([x, y, z, r]): PaintSpec => ({ bone: 'cap', on: ['cap'], kind: 'sphere', at: [x, y, z], radius: r, color: '#fff8ee', soft: 0.12 }),
33
+ ),
34
+ { bone: 'body', on: ['stem'], kind: 'sphere', at: [-0.13, 0.22, 0.14], radius: 0.045, color: '#ff9eb0', soft: 0.6, opacity: 0.8 },
35
+ { bone: 'body', on: ['stem'], kind: 'sphere', at: [0.13, 0.22, 0.14], radius: 0.045, color: '#ff9eb0', soft: 0.6, opacity: 0.8 },
36
+ ],
37
+ eyes: { kind: 'bead', bone: 'body', at: [[-0.07, 0.29, 0.165], [0.07, 0.29, 0.165]], radii: [0.028, 0.042, 0.018], material: 'bead' },
38
+ face: { kind: 'mouth', bone: 'body', on: ['stem'], at: [0, 0.21, 0.19], width: 0.04, color: '#4a2a22', tongue: '#ff7d97' },
39
+ anchors: {
40
+ top: { bone: 'cap', at: [0.1, 0.38, 0] },
41
+ mouth: { bone: 'body', at: [0, 0.21, 0.21] },
42
+ ear: { bone: 'body', at: [-0.2, 0.3, 0] },
43
+ feet: { bone: 'root', at: [0, 0.02, 0.15] },
44
+ },
45
+ acting: {
46
+ thinking: { cap: { rz: 0.15 } },
47
+ sleeping: { cap: { rx: 0.2, rz: 0.15 } },
48
+ error: { cap: { rz: [0, 0.12, 9, 0] } },
49
+ surprised: { cap: { rx: -0.15 } },
50
+ sad: { cap: { rx: 0.3 } },
51
+ celebrating: { cap: { rz: [0, 0.15, 4, 0] } },
52
+ },
53
+ fx: {
54
+ /* puffs of spores when it lands */
55
+ land: [{ glyph: 'mote', anchor: 'top', rate: 6, spread: 0.2, velocity: [0, 0.2, 0], jitter: 0.2, wobble: 0.08, life: [1, 1.5], size: [0.025, 0.01], color: '#ffe8a3', glow: true }],
56
+ },
57
+ };
58
+
59
+ export default cap;
@@ -0,0 +1,74 @@
1
+ import type { CharacterSpec } from 'wobnimo';
2
+
3
+ /** A sleepy cloud in brand blue, wearing big headphones. */
4
+ export const drift: CharacterSpec = {
5
+ id: 'drift',
6
+ name: 'Drift',
7
+ tagline: 'A sleepy blue cloud that floats along to the music in its headphones',
8
+ accent: '#4f7cff',
9
+ frame: { target: 0.63, radius: 0.84 },
10
+ bound: { y: 0.6, radius: 0.69 },
11
+ motion: { float: 0.18, hop: 0.1, squash: 1.3, snap: 0.75, talkSquash: 0.8 },
12
+ materials: {
13
+ cloud: { color: '#9db8ff', f0: 0.03, spec: 0.35, shininess: 20, rim: 1.1, sss: 0.55, sssColor: '#dbe6ff', sheen: 0.3 },
14
+ band: { color: '#20253a', f0: 0.06, spec: 1.4, shininess: 120, rim: 0.4, gloss: 0.7 },
15
+ cup: { color: '#4f7cff', f0: 0.08, spec: 1.6, shininess: 160, rim: 0.5, gloss: 0.8 },
16
+ cushion: { color: '#2a2f45', f0: 0.03, spec: 0.3, shininess: 20, rim: 0.3, sheen: 0.6 },
17
+ },
18
+ bones: [
19
+ { name: 'body', pivot: [0, 0, 0], drive: { rx: [['pitch', -0.4]], ry: [['yaw', 0.6]], rz: [['roll', 0.7]] }, wave: { rz: [0.04, 0.35, 0] } },
20
+ /* the head bobs to the beat on its own */
21
+ { name: 'phones', parent: 'body', pivot: [0, 0.55, 0], wave: { rz: [0.03, 1.1, 0] } },
22
+ ],
23
+ parts: [
24
+ /* a cluster of puffs melted together, flatter underneath */
25
+ { bone: 'body', shape: 'sphere', at: [0, 0.52, 0], radius: 0.32, material: 'cloud' },
26
+ { bone: 'body', shape: 'sphere', at: [-0.3, 0.42, 0], radius: 0.22, blend: 0.12, material: 'cloud' },
27
+ { bone: 'body', shape: 'sphere', at: [0.31, 0.43, 0], radius: 0.23, blend: 0.12, material: 'cloud' },
28
+ { bone: 'body', shape: 'sphere', at: [-0.14, 0.72, -0.03], radius: 0.2, blend: 0.12, material: 'cloud' },
29
+ { bone: 'body', shape: 'sphere', at: [0.16, 0.74, -0.04], radius: 0.22, blend: 0.12, material: 'cloud' },
30
+ { bone: 'body', shape: 'ellipsoid', at: [0, 0.34, 0], radii: [0.5, 0.12, 0.3], blend: 0.1, material: 'cloud' },
31
+ /* headphones: a band over the top, a cup and cushion on each side */
32
+ { bone: 'phones', shape: 'capsule', from: [-0.47, 0.0, 0], to: [-0.4, 0.26, 0], radius: 0.028, material: 'band' },
33
+ { bone: 'phones', shape: 'capsule', from: [-0.4, 0.26, 0], to: [-0.18, 0.42, 0], radius: 0.028, blend: 0.02, material: 'band' },
34
+ { bone: 'phones', shape: 'capsule', from: [-0.18, 0.42, 0], to: [0.18, 0.42, 0], radius: 0.028, blend: 0.02, material: 'band' },
35
+ { bone: 'phones', shape: 'capsule', from: [0.18, 0.42, 0], to: [0.4, 0.26, 0], radius: 0.028, blend: 0.02, material: 'band' },
36
+ { bone: 'phones', shape: 'capsule', from: [0.4, 0.26, 0], to: [0.47, 0.0, 0], radius: 0.028, material: 'band' },
37
+ { bone: 'phones', shape: 'cylinder', at: [-0.5, -0.04, 0], rot: [0, 0, Math.PI / 2], radius: 0.12, half: 0.05, round: 0.025, material: 'cup' },
38
+ { bone: 'phones', shape: 'cylinder', at: [0.5, -0.04, 0], rot: [0, 0, Math.PI / 2], radius: 0.12, half: 0.05, round: 0.025, material: 'cup' },
39
+ { bone: 'phones', shape: 'cylinder', at: [-0.44, -0.04, 0], rot: [0, 0, Math.PI / 2], radius: 0.1, half: 0.025, round: 0.02, material: 'cushion' },
40
+ { bone: 'phones', shape: 'cylinder', at: [0.44, -0.04, 0], rot: [0, 0, Math.PI / 2], radius: 0.1, half: 0.025, round: 0.02, material: 'cushion' },
41
+ ],
42
+ paints: [
43
+ { bone: 'body', on: ['cloud'], kind: 'sphere', at: [-0.2, 0.46, 0.27], radius: 0.06, color: '#ff9ec4', soft: 0.6, opacity: 0.75 },
44
+ { bone: 'body', on: ['cloud'], kind: 'sphere', at: [0.2, 0.46, 0.27], radius: 0.06, color: '#ff9ec4', soft: 0.6, opacity: 0.75 },
45
+ ],
46
+ eyes: {
47
+ kind: 'ball', bone: 'body', at: [[-0.11, 0.56, 0.27], [0.11, 0.56, 0.27]],
48
+ radius: 0.05, iris: '#1d2550', irisSize: 0.8, pupilSize: 0.5, lid: 'cloud',
49
+ },
50
+ face: { kind: 'mouth', bone: 'body', on: ['cloud'], at: [0, 0.45, 0.31], width: 0.06, color: '#24305e', tongue: '#ff8fae' },
51
+ anchors: {
52
+ top: { bone: 'body', at: [0.18, 0.98, 0.05] },
53
+ mouth: { bone: 'body', at: [0, 0.45, 0.33] },
54
+ ear: { bone: 'phones', at: [-0.56, -0.04, 0] },
55
+ center: { bone: 'body', at: [0, 0.5, 0] },
56
+ },
57
+ acting: {
58
+ idle: { phones: { rz: [0, 0.04, 1.6, 0] } },
59
+ thinking: { phones: { rz: 0.12 }, body: { rz: 0.06 } },
60
+ listening: { phones: { rz: -0.12 } },
61
+ speaking: { phones: { rz: [0, 0.05, 2.2, 0] } },
62
+ sleeping: { phones: { rz: 0.18 }, body: { rz: 0.1 } },
63
+ working: { phones: { rz: [0, 0.06, 3.2, 0] } },
64
+ celebrating: { phones: { rz: [0, 0.12, 3, 0] } },
65
+ sad: { phones: { rz: -0.1 }, body: { rx: 0.1 } },
66
+ },
67
+ fx: {
68
+ /* music notes float out of the cups while it's idle */
69
+ idle: [{ glyph: 'note', anchor: 'ear', rate: 0.6, velocity: [-0.12, 0.25, 0.04], jitter: 0.08, wobble: 0.05, life: [1.4, 1.8], size: [0.05, 0.03], color: '#4f7cff' }],
70
+ sleeping: [{ glyph: 'cloud', anchor: 'top', rate: 0.5, velocity: [0.05, 0.12, 0], jitter: 0.04, life: [2, 2.5], size: [0.04, 0.08], color: '#dbe6ff' }],
71
+ },
72
+ };
73
+
74
+ export default drift;
@@ -0,0 +1,78 @@
1
+ import type { CharacterSpec } from 'wobnimo';
2
+
3
+ /** A fox cub with a big fluffy tail. */
4
+ export const ember: CharacterSpec = {
5
+ id: 'ember',
6
+ name: 'Ember',
7
+ tagline: 'A fox cub with pointed ears and a big fluffy tail that never stops swishing',
8
+ accent: '#f07a2a',
9
+ frame: { target: 0.48, radius: 0.72 },
10
+ bound: { y: 0.38, radius: 0.85 },
11
+ motion: { hop: 0.14, squash: 1, snap: 1.1, talkSquash: 0.4 },
12
+ materials: {
13
+ fur: { color: '#f07a2a', f0: 0.03, spec: 0.4, shininess: 20, rim: 1, sheen: 0.7, surface: { kind: 'fur', scale: 90, strength: 0.4, bone: 'head' } },
14
+ bodyFur: { color: '#f07a2a', shadeOf: 'fur', f0: 0.03, spec: 0.4, shininess: 20, rim: 1, sheen: 0.7, surface: { kind: 'fur', scale: 90, strength: 0.4 } },
15
+ tailFur: { color: '#f07a2a', shadeOf: 'fur', f0: 0.03, spec: 0.4, shininess: 20, rim: 1, sheen: 0.8, surface: { kind: 'fur', scale: 70, strength: 0.5, bone: 'tail' } },
16
+ dark: { color: '#3a2318', f0: 0.03, spec: 0.4, shininess: 20, rim: 0.6, sheen: 0.5 },
17
+ nose: { color: '#1d1410', f0: 0.06, spec: 1.8, shininess: 200, rim: 0.3, gloss: 0.9 },
18
+ },
19
+ bones: [
20
+ { name: 'body', pivot: [0, 0, 0], drive: { ry: [['yaw', 0.2]], rz: [['roll', 0.3]] } },
21
+ { name: 'head', parent: 'body', pivot: [0, 0.48, 0.02], drive: { rx: [['pitch', -1]], ry: [['yaw', 0.8]], rz: [['roll', 0.7]] } },
22
+ { name: 'earL', parent: 'head', pivot: [-0.14, 0.28, 0], rest: { rz: 0.3 }, jiggle: { axis: [0, 1, 0], length: 0.16, freq: 3.5, damping: 0.2, maxAngle: 0.4 } },
23
+ { name: 'earR', parent: 'head', pivot: [0.14, 0.28, 0], rest: { rz: -0.3 }, jiggle: { axis: [0, 1, 0], length: 0.16, freq: 3.5, damping: 0.2, maxAngle: 0.4 } },
24
+ { name: 'tail', parent: 'body', pivot: [0.15, 0.12, -0.15], rest: { rz: -0.9, rx: -0.4 }, wave: { ry: [0.35, 0.8, 0] }, jiggle: { axis: [0, 1, 0], length: 0.35, freq: 1.8, damping: 0.18, maxAngle: 0.6 } },
25
+ ],
26
+ parts: [
27
+ { bone: 'body', shape: 'ellipsoid', at: [0, 0.25, 0], radii: [0.22, 0.25, 0.2], material: 'bodyFur' },
28
+ /* little legs */
29
+ { bone: 'body', shape: 'capsule', from: [-0.1, 0.12, 0.08], to: [-0.1, 0.04, 0.12], radius: 0.06, blend: 0.05, material: 'dark' },
30
+ { bone: 'body', shape: 'capsule', from: [0.1, 0.12, 0.08], to: [0.1, 0.04, 0.12], radius: 0.06, blend: 0.05, material: 'dark' },
31
+ /* a wide head with a pointed muzzle and cheek fluff */
32
+ { bone: 'head', shape: 'ellipsoid', at: [0, 0.12, 0], radii: [0.27, 0.22, 0.23], blend: 0.1, material: 'fur' },
33
+ { bone: 'head', shape: 'roundCone', from: [0, 0.07, 0.1], to: [0, 0.05, 0.3], r1: 0.12, r2: 0.04, blend: 0.08, material: 'fur' },
34
+ { bone: 'head', shape: 'sphere', at: [0, 0.06, 0.33], radius: 0.035, material: 'nose' },
35
+ { bone: 'head', shape: 'ellipsoid', at: [-0.22, 0.02, 0.06], radii: [0.09, 0.07, 0.08], blend: 0.06, material: 'fur' },
36
+ { bone: 'head', shape: 'ellipsoid', at: [0.22, 0.02, 0.06], radii: [0.09, 0.07, 0.08], blend: 0.06, material: 'fur' },
37
+ /* tall pointed ears with dark tips */
38
+ { bone: 'earL', shape: 'roundCone', from: [0, 0, 0], to: [0, 0.18, 0], r1: 0.08, r2: 0.015, material: 'fur' },
39
+ { bone: 'earR', shape: 'roundCone', from: [0, 0, 0], to: [0, 0.18, 0], r1: 0.08, r2: 0.015, material: 'fur' },
40
+ /* the tail: a big plume */
41
+ { bone: 'tail', shape: 'roundCone', from: [0, 0, 0], to: [0, 0.3, 0], r1: 0.06, r2: 0.13, material: 'tailFur' },
42
+ { bone: 'tail', shape: 'sphere', at: [0, 0.36, 0], radius: 0.11, blend: 0.08, material: 'tailFur' },
43
+ ],
44
+ paints: [
45
+ { bone: 'body', on: ['bodyFur'], kind: 'ellipse', at: [0, 0.26, 0.1], radii: [0.13, 0.17], color: '#fff3e6', soft: 0.25 },
46
+ { bone: 'head', on: ['fur'], kind: 'sphere', at: [0, 0.0, 0.25], radius: 0.13, color: '#fff3e6', soft: 0.25 },
47
+ { bone: 'head', on: ['fur'], kind: 'sphere', at: [-0.2, -0.02, 0.12], radius: 0.1, color: '#fff3e6', soft: 0.3 },
48
+ { bone: 'head', on: ['fur'], kind: 'sphere', at: [0.2, -0.02, 0.12], radius: 0.1, color: '#fff3e6', soft: 0.3 },
49
+ { bone: 'earL', on: ['fur'], kind: 'sphere', at: [0, 0.2, 0], radius: 0.07, color: '#3a2318', soft: 0.3 },
50
+ { bone: 'earR', on: ['fur'], kind: 'sphere', at: [0, 0.2, 0], radius: 0.07, color: '#3a2318', soft: 0.3 },
51
+ { bone: 'earL', on: ['fur'], kind: 'ellipse', at: [0, 0.07, 0.05], radii: [0.035, 0.07], color: '#ffd9c2', soft: 0.4 },
52
+ { bone: 'earR', on: ['fur'], kind: 'ellipse', at: [0, 0.07, 0.05], radii: [0.035, 0.07], color: '#ffd9c2', soft: 0.4 },
53
+ { bone: 'tail', on: ['tailFur'], kind: 'sphere', at: [0, 0.46, 0], radius: 0.13, color: '#fff3e6', soft: 0.2 },
54
+ ],
55
+ eyes: { kind: 'ball', bone: 'head', at: [[-0.1, 0.15, 0.19], [0.1, 0.15, 0.19]], radius: 0.055, iris: '#2b1a10', irisSize: 0.82, pupilSize: 0.52, lid: 'fur' },
56
+ face: { kind: 'mouth', bone: 'head', on: ['fur'], at: [0, 0, 0.277], width: 0.045, color: '#3a2318', tongue: '#ff7d8a' },
57
+ anchors: {
58
+ top: { bone: 'head', at: [0.12, 0.45, 0.05] },
59
+ mouth: { bone: 'head', at: [0, 0.0, 0.33] },
60
+ ear: { bone: 'earL', at: [0, 0.1, 0] },
61
+ feet: { bone: 'root', at: [0, 0.02, 0.12] },
62
+ },
63
+ acting: {
64
+ idle: { tail: { ry: [0, 0.2, 0.7, 0] } },
65
+ thinking: { earL: { rz: 0.6 }, head: { rz: 0.12 } },
66
+ listening: { earL: { rx: -0.3 }, earR: { rx: -0.3 } },
67
+ speaking: { tail: { ry: [0, 0.3, 1.5, 0] } },
68
+ sleeping: { earL: { rz: 0.8 }, earR: { rz: -0.8 }, tail: { rz: -1.4 } },
69
+ working: { tail: { ry: [0, 0.4, 3, 0] } },
70
+ error: { earL: { rz: 1.1 }, earR: { rz: -1.1 } },
71
+ surprised: { earL: { rz: 0.05 }, earR: { rz: -0.05 }, tail: { rx: -0.8 } },
72
+ celebrating: { tail: { ry: [0, 0.6, 5, 0] } },
73
+ sad: { earL: { rz: 1, rx: 0.4 }, earR: { rz: -1, rx: 0.4 }, tail: { rz: -1.1 } },
74
+ happy: { tail: { ry: [0, 0.6, 6, 0] } },
75
+ },
76
+ };
77
+
78
+ export default ember;