@originkit/avatars 0.0.0-stage → 0.1.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 (168) hide show
  1. package/GUIDE.md +44 -0
  2. package/LICENSE +58 -0
  3. package/README.md +119 -2
  4. package/bin/avatars.js +65 -0
  5. package/dist/art.d.ts +43 -0
  6. package/dist/art.js +35 -0
  7. package/dist/auras/calming.d.ts +18 -0
  8. package/dist/auras/calming.js +30 -0
  9. package/dist/auras/controls.d.ts +2 -0
  10. package/dist/auras/controls.js +60 -0
  11. package/dist/auras/index.d.ts +119 -0
  12. package/dist/auras/index.js +355 -0
  13. package/dist/auras/skies.d.ts +13 -0
  14. package/dist/auras/skies.js +22 -0
  15. package/dist/blobs/color.d.ts +19 -0
  16. package/dist/blobs/color.js +113 -0
  17. package/dist/blobs/controls.d.ts +2 -0
  18. package/dist/blobs/controls.js +77 -0
  19. package/dist/blobs/index.d.ts +5 -0
  20. package/dist/blobs/index.js +107 -0
  21. package/dist/blobs/paths.d.ts +33 -0
  22. package/dist/blobs/paths.js +102 -0
  23. package/dist/blobs/shapes.d.ts +46 -0
  24. package/dist/blobs/shapes.js +186 -0
  25. package/dist/blobs/variance.d.ts +22 -0
  26. package/dist/blobs/variance.js +42 -0
  27. package/dist/bots/attachments.d.ts +24 -0
  28. package/dist/bots/attachments.js +119 -0
  29. package/dist/bots/calming.d.ts +4 -0
  30. package/dist/bots/calming.js +19 -0
  31. package/dist/bots/controls.d.ts +2 -0
  32. package/dist/bots/controls.js +78 -0
  33. package/dist/bots/faces.d.ts +23 -0
  34. package/dist/bots/faces.js +122 -0
  35. package/dist/bots/heads.d.ts +15 -0
  36. package/dist/bots/heads.js +66 -0
  37. package/dist/bots/index.d.ts +5 -0
  38. package/dist/bots/index.js +47 -0
  39. package/dist/bots/palette.d.ts +15 -0
  40. package/dist/bots/palette.js +30 -0
  41. package/dist/bots/paths.d.ts +25 -0
  42. package/dist/bots/paths.js +89 -0
  43. package/dist/bots/trim.d.ts +12 -0
  44. package/dist/bots/trim.js +37 -0
  45. package/dist/bubbles/calming.d.ts +7 -0
  46. package/dist/bubbles/calming.js +19 -0
  47. package/dist/bubbles/controls.d.ts +2 -0
  48. package/dist/bubbles/controls.js +69 -0
  49. package/dist/bubbles/index.d.ts +65 -0
  50. package/dist/bubbles/index.js +279 -0
  51. package/dist/buddies/calming.d.ts +8 -0
  52. package/dist/buddies/calming.js +18 -0
  53. package/dist/buddies/controls.d.ts +2 -0
  54. package/dist/buddies/controls.js +35 -0
  55. package/dist/buddies/index.d.ts +113 -0
  56. package/dist/buddies/index.js +363 -0
  57. package/dist/colors.d.ts +20 -0
  58. package/dist/colors.js +41 -0
  59. package/dist/combinations.d.ts +9 -0
  60. package/dist/combinations.js +28 -0
  61. package/dist/container.d.ts +14 -0
  62. package/dist/container.js +67 -0
  63. package/dist/controls.d.ts +128 -0
  64. package/dist/controls.js +170 -0
  65. package/dist/critters/calming.d.ts +8 -0
  66. package/dist/critters/calming.js +18 -0
  67. package/dist/critters/controls.d.ts +2 -0
  68. package/dist/critters/controls.js +49 -0
  69. package/dist/critters/index.d.ts +113 -0
  70. package/dist/critters/index.js +307 -0
  71. package/dist/doodles/calming.d.ts +7 -0
  72. package/dist/doodles/calming.js +18 -0
  73. package/dist/doodles/controls.d.ts +2 -0
  74. package/dist/doodles/controls.js +50 -0
  75. package/dist/doodles/index.d.ts +66 -0
  76. package/dist/doodles/index.js +236 -0
  77. package/dist/faces/adventurer-neutral.json +3168 -0
  78. package/dist/faces/calming.d.ts +8 -0
  79. package/dist/faces/calming.js +20 -0
  80. package/dist/faces/controls.d.ts +2 -0
  81. package/dist/faces/controls.js +38 -0
  82. package/dist/faces/index.d.ts +44 -0
  83. package/dist/faces/index.js +108 -0
  84. package/dist/glances/calming.d.ts +8 -0
  85. package/dist/glances/calming.js +16 -0
  86. package/dist/glances/controls.d.ts +2 -0
  87. package/dist/glances/controls.js +27 -0
  88. package/dist/glances/index.d.ts +54 -0
  89. package/dist/glances/index.js +79 -0
  90. package/dist/glyphs/calming.d.ts +8 -0
  91. package/dist/glyphs/calming.js +17 -0
  92. package/dist/glyphs/controls.d.ts +2 -0
  93. package/dist/glyphs/controls.js +55 -0
  94. package/dist/glyphs/index.d.ts +62 -0
  95. package/dist/glyphs/index.js +197 -0
  96. package/dist/grins/calming.d.ts +8 -0
  97. package/dist/grins/calming.js +21 -0
  98. package/dist/grins/controls.d.ts +2 -0
  99. package/dist/grins/controls.js +33 -0
  100. package/dist/grins/index.d.ts +81 -0
  101. package/dist/grins/index.js +240 -0
  102. package/dist/gummies/art.d.ts +77 -0
  103. package/dist/gummies/art.js +168 -0
  104. package/dist/gummies/calming.d.ts +8 -0
  105. package/dist/gummies/calming.js +21 -0
  106. package/dist/gummies/controls.d.ts +2 -0
  107. package/dist/gummies/controls.js +53 -0
  108. package/dist/gummies/index.d.ts +37 -0
  109. package/dist/gummies/index.js +283 -0
  110. package/dist/history.d.ts +21 -0
  111. package/dist/history.js +48 -0
  112. package/dist/index.d.ts +13 -0
  113. package/dist/index.js +16 -0
  114. package/dist/kinds.d.ts +30 -0
  115. package/dist/kinds.js +266 -0
  116. package/dist/kitties/calming.d.ts +8 -0
  117. package/dist/kitties/calming.js +19 -0
  118. package/dist/kitties/controls.d.ts +2 -0
  119. package/dist/kitties/controls.js +43 -0
  120. package/dist/kitties/index.d.ts +181 -0
  121. package/dist/kitties/index.js +673 -0
  122. package/dist/knits/calming.d.ts +7 -0
  123. package/dist/knits/calming.js +19 -0
  124. package/dist/knits/controls.d.ts +2 -0
  125. package/dist/knits/controls.js +32 -0
  126. package/dist/knits/index.d.ts +74 -0
  127. package/dist/knits/index.js +445 -0
  128. package/dist/mallows/calming.d.ts +8 -0
  129. package/dist/mallows/calming.js +19 -0
  130. package/dist/mallows/controls.d.ts +2 -0
  131. package/dist/mallows/controls.js +45 -0
  132. package/dist/mallows/index.d.ts +111 -0
  133. package/dist/mallows/index.js +454 -0
  134. package/dist/peeks/calming.d.ts +8 -0
  135. package/dist/peeks/calming.js +21 -0
  136. package/dist/peeks/controls.d.ts +2 -0
  137. package/dist/peeks/controls.js +54 -0
  138. package/dist/peeks/index.d.ts +80 -0
  139. package/dist/peeks/index.js +225 -0
  140. package/dist/pixels/calming.d.ts +8 -0
  141. package/dist/pixels/calming.js +22 -0
  142. package/dist/pixels/controls.d.ts +3 -0
  143. package/dist/pixels/controls.js +82 -0
  144. package/dist/pixels/index.d.ts +34 -0
  145. package/dist/pixels/index.js +174 -0
  146. package/dist/pixels/palette.d.ts +29 -0
  147. package/dist/pixels/palette.js +107 -0
  148. package/dist/pixels/sprites.d.ts +42 -0
  149. package/dist/pixels/sprites.js +154 -0
  150. package/dist/possibilities.d.ts +39 -0
  151. package/dist/possibilities.js +88 -0
  152. package/dist/shapes/calming.d.ts +7 -0
  153. package/dist/shapes/calming.js +19 -0
  154. package/dist/shapes/controls.d.ts +2 -0
  155. package/dist/shapes/controls.js +41 -0
  156. package/dist/shapes/index.d.ts +44 -0
  157. package/dist/shapes/index.js +104 -0
  158. package/dist/share.d.ts +21 -0
  159. package/dist/share.js +83 -0
  160. package/dist/traits.d.ts +34 -0
  161. package/dist/traits.js +58 -0
  162. package/dist/types.d.ts +99 -0
  163. package/dist/types.js +1 -0
  164. package/dist/variants.d.ts +11 -0
  165. package/dist/variants.js +41 -0
  166. package/mcp/server.js +7 -0
  167. package/mcp/tools.js +70 -0
  168. package/package.json +54 -4
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The public entry, shared by the npm package, the CLI, the MCP server and the studio's
3
+ * export: a style and a name in, an SVG out. The same inputs always give the same SVG.
4
+ */
5
+ import type { Overrides } from "./traits.ts";
6
+ export type { Overrides } from "./traits.ts";
7
+ /** Every style, in the studio's order. */
8
+ export declare const styles: {
9
+ id: string;
10
+ label: string;
11
+ }[];
12
+ /** The avatar for `name` in `style`. Throws on a style that doesn't exist. */
13
+ export declare function createAvatar(style: string, name: string, overrides?: Overrides): string;
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The public entry, shared by the npm package, the CLI, the MCP server and the studio's
3
+ * export: a style and a name in, an SVG out. The same inputs always give the same SVG.
4
+ */
5
+ import { KINDS } from "./kinds.js";
6
+ /** Every style, in the studio's order. */
7
+ export const styles = KINDS.map(({ id, label }) => ({ id, label }));
8
+ /** CC BY 4.0 asks for a credit wherever the Faces art goes, so it travels with the file. */
9
+ const FACES_CREDIT = '<!-- Faces art: "Adventurer Neutral" by Lisa Wischofsky, CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/), changed. -->\n';
10
+ /** The avatar for `name` in `style`. Throws on a style that doesn't exist. */
11
+ export function createAvatar(style, name, overrides) {
12
+ const kind = KINDS.find((k) => k.id === style);
13
+ if (!kind)
14
+ throw new Error(`Unknown style "${style}". Styles: ${styles.map((s) => s.id).join(", ")}`);
15
+ return (style === "faces" ? FACES_CREDIT : "") + kind.svg(name, overrides);
16
+ }
@@ -0,0 +1,30 @@
1
+ /** The avatar types a visitor can choose from. */
2
+ import type { ControlBuilder } from "./controls.ts";
3
+ import type { Overrides } from "./traits.ts";
4
+ import type { AvatarParts } from "./types.ts";
5
+ export interface AvatarKind {
6
+ id: string;
7
+ label: string;
8
+ group: string;
9
+ hint: string;
10
+ defaultName: string;
11
+ controls: ControlBuilder;
12
+ /** What it is, its face and its colour, shown up front in order. The rest sit under More options. */
13
+ essentials: string[];
14
+ /** The controls that set a look apart most. Each variant takes a different value of each. */
15
+ styleKeys: string[];
16
+ /** Settings for how it is shown rather than what it looks like, which thumbnails leave out. */
17
+ displayKeys?: string[];
18
+ /** A still picture, for thumbnails and as the fallback when 3D cannot run. */
19
+ svg(name: string, overrides?: Overrides): string;
20
+ /** Present on kinds drawn in 3D. */
21
+ parts?(name: string, overrides?: Overrides): AvatarParts;
22
+ /** Kept, and tested, but not shown on the canvas for now. */
23
+ hidden?: boolean;
24
+ /** Never moves, so the panel leaves out Motion. */
25
+ still?: boolean;
26
+ }
27
+ export declare const KINDS: AvatarKind[];
28
+ /** The kinds shown on the canvas, which leaves out any hidden for now. */
29
+ export declare const SHOWN: AvatarKind[];
30
+ export declare const toDataUri: (svg: string) => string;
package/dist/kinds.js ADDED
@@ -0,0 +1,266 @@
1
+ /** The avatar types a visitor can choose from. */
2
+ import { controls as auraControls } from "./auras/controls.js";
3
+ import { auraSvg } from "./auras/index.js";
4
+ import { controls as blobControls } from "./blobs/controls.js";
5
+ import { blobParts, generateBlob } from "./blobs/index.js";
6
+ import { controls as bubbleControls } from "./bubbles/controls.js";
7
+ import { bubbleSvg } from "./bubbles/index.js";
8
+ import { controls as botControls } from "./bots/controls.js";
9
+ import { botParts, generateBot } from "./bots/index.js";
10
+ import { controls as buddyControls } from "./buddies/controls.js";
11
+ import { buddySvg } from "./buddies/index.js";
12
+ import { controls as doodleControls } from "./doodles/controls.js";
13
+ import { animalControls } from "./kitties/controls.js";
14
+ import { animalSvg } from "./kitties/index.js";
15
+ import { doodleSvg } from "./doodles/index.js";
16
+ import { controls as faceControls } from "./faces/controls.js";
17
+ import { faceSvg } from "./faces/index.js";
18
+ import { controls as critterControls } from "./critters/controls.js";
19
+ import { critterSvg } from "./critters/index.js";
20
+ import { controls as glanceControls } from "./glances/controls.js";
21
+ import { controls as knitControls } from "./knits/controls.js";
22
+ import { knitSvg } from "./knits/index.js";
23
+ import { controls as grinControls } from "./grins/controls.js";
24
+ import { grinSvg } from "./grins/index.js";
25
+ import { glanceSvg } from "./glances/index.js";
26
+ import { controls as glyphControls } from "./glyphs/controls.js";
27
+ import { controls as gummyControls } from "./gummies/controls.js";
28
+ import { gummyParts, gummySvg } from "./gummies/index.js";
29
+ import { glyphSvg } from "./glyphs/index.js";
30
+ import { controls as mallowControls } from "./mallows/controls.js";
31
+ import { mallowParts, mallowSvg } from "./mallows/index.js";
32
+ import { controls as peekControls } from "./peeks/controls.js";
33
+ import { peekSvg } from "./peeks/index.js";
34
+ import { colorControls } from "./pixels/controls.js";
35
+ import { controls as shapeControls } from "./shapes/controls.js";
36
+ import { shapeSvg } from "./shapes/index.js";
37
+ import { pixelSvg } from "./pixels/index.js";
38
+ export const KINDS = [
39
+ {
40
+ id: "bots",
41
+ label: "Bots",
42
+ group: "3D",
43
+ hint: "Move your mouse and it looks at you",
44
+ defaultName: "Nova",
45
+ controls: botControls,
46
+ // The container's size and colour join it only while it's on, which may make 8.
47
+ essentials: ["head", "eye", "paint"],
48
+ styleKeys: ["head"],
49
+ displayKeys: ["container.size"],
50
+ svg: generateBot,
51
+ parts: botParts,
52
+ },
53
+ {
54
+ id: "blobs",
55
+ label: "Blobs",
56
+ group: "3D",
57
+ hint: "Move your mouse and it looks at you",
58
+ defaultName: "Rex-7",
59
+ controls: blobControls,
60
+ // As with bots, the container's size and colour join it only while it's on.
61
+ essentials: ["shape", "hue", "tone"],
62
+ styleKeys: ["shape"],
63
+ displayKeys: ["container.size"],
64
+ svg: generateBlob,
65
+ parts: blobParts,
66
+ },
67
+ {
68
+ id: "gummies",
69
+ label: "Gummies",
70
+ group: "3D",
71
+ hint: "A jelly in 3D, lit from inside. It watches you, and boings when tapped",
72
+ defaultName: "Juju",
73
+ controls: gummyControls,
74
+ // Its colour controls and Possibilities were asked for up front, so it shows 9.
75
+ essentials: ["body", "face", "glow"],
76
+ styleKeys: ["body", "face", "topper", "glow"],
77
+ svg: gummySvg,
78
+ parts: gummyParts,
79
+ },
80
+ {
81
+ id: "mallows",
82
+ label: "Mallows",
83
+ group: "3D",
84
+ hint: "Soft clay in 3D, a bun, a ghost or a cloud, and every one feels something different. It watches you, and boings when tapped",
85
+ defaultName: "Momo",
86
+ controls: mallowControls,
87
+ // Eyes and Pose were asked for up front beside the rest, so it shows 8. As with bots, the
88
+ // container's size and colour join it only while it's on.
89
+ essentials: ["type", "face", "colour"],
90
+ // One bun for every name, as asked, so only its feeling sets variants apart.
91
+ styleKeys: ["face"],
92
+ displayKeys: ["container.size"],
93
+ svg: mallowSvg,
94
+ parts: mallowParts,
95
+ },
96
+ {
97
+ id: "faces",
98
+ label: "Faces",
99
+ group: "Illustrated",
100
+ hint: "Its eyes follow you. Tap it to see what it does",
101
+ defaultName: "Maya",
102
+ controls: faceControls,
103
+ essentials: ["eyes", "mouth", "skin"],
104
+ styleKeys: ["mouth"],
105
+ svg: faceSvg,
106
+ },
107
+ {
108
+ id: "bubbles",
109
+ label: "Bubbles",
110
+ group: "Illustrated",
111
+ hint: "Its eyes follow you. Write anything on it",
112
+ defaultName: "Felix",
113
+ controls: bubbleControls,
114
+ essentials: ["shape", "mouth", "palette"],
115
+ styleKeys: ["shape", "palette"],
116
+ svg: bubbleSvg,
117
+ },
118
+ {
119
+ id: "pixels",
120
+ label: "Pixels",
121
+ group: "Pixel",
122
+ hint: "Its eyes follow you. Hover over it and it perks up",
123
+ defaultName: "Finn",
124
+ controls: colorControls,
125
+ essentials: ["hair", "hair.color", "hat.color", "skin"],
126
+ styleKeys: ["hair"],
127
+ svg: (name, overrides) => pixelSvg(name, "color", overrides),
128
+ },
129
+ {
130
+ id: "glyphs",
131
+ label: "Glyphs",
132
+ group: "Illustrated",
133
+ hint: "Its eyes follow you. Hover over it and it grows",
134
+ defaultName: "Priya",
135
+ controls: glyphControls,
136
+ essentials: ["shape", "fill", "tile"],
137
+ styleKeys: ["shape"],
138
+ svg: glyphSvg,
139
+ },
140
+ {
141
+ id: "peeks",
142
+ label: "Peeks",
143
+ group: "Illustrated",
144
+ hint: "It's watching you. Tap it to see what it does",
145
+ defaultName: "Milo",
146
+ controls: peekControls,
147
+ // Possibilities was asked for up front beside the rest, so it shows 7.
148
+ essentials: ["body", "eye.kind", "tile"],
149
+ styleKeys: ["body", "pose", "tile"],
150
+ svg: peekSvg,
151
+ },
152
+ {
153
+ id: "doodles",
154
+ label: "Doodles",
155
+ group: "Illustrated",
156
+ hint: "Its eyes follow you. Hover over it and it perks up",
157
+ defaultName: "Kiko",
158
+ controls: doodleControls,
159
+ essentials: ["mood", "tile", "colourful"],
160
+ // Colourful is off until switched on, so Colourway isn't always there to step through.
161
+ styleKeys: ["mood", "tile"],
162
+ svg: doodleSvg,
163
+ },
164
+ {
165
+ id: "animals",
166
+ label: "Animals",
167
+ group: "Illustrated",
168
+ hint: "A cat, a dog, an owl, a bear or a tiger, drawn like the cats. Hover over it and its ears twitch",
169
+ defaultName: "Biscuit",
170
+ controls: animalControls,
171
+ essentials: ["animal", "mood", "tile"],
172
+ styleKeys: ["mood", "ears", "tile"],
173
+ svg: animalSvg,
174
+ },
175
+ {
176
+ id: "buddies",
177
+ // Hidden for now, as asked. Its code stays as it was.
178
+ hidden: true,
179
+ label: "Buddies",
180
+ group: "Illustrated",
181
+ hint: "A tabby or a calico, up to something. Hover over it and its eyes widen",
182
+ defaultName: "Mochi",
183
+ controls: buddyControls,
184
+ essentials: ["character", "mood", "tile"],
185
+ styleKeys: ["gesture", "mood", "tile"],
186
+ svg: buddySvg,
187
+ },
188
+ {
189
+ id: "shapes",
190
+ label: "Shapes",
191
+ group: "Illustrated",
192
+ hint: "A face put together from bold shapes. Its eyes follow you. Tap it and they hop",
193
+ defaultName: "Lumi",
194
+ controls: shapeControls,
195
+ essentials: ["eye.left", "eye.right", "mouth", "tile"],
196
+ styleKeys: ["eye.left", "eye.right", "mouth", "colourway"],
197
+ svg: shapeSvg,
198
+ },
199
+ {
200
+ id: "critters",
201
+ label: "Critters",
202
+ group: "Illustrated",
203
+ hint: "A monster, a cyclops, a bear, a duck, a chick, an imp or a grump, up close. It watches you and blinks, and pops when tapped",
204
+ defaultName: "Gobo",
205
+ controls: critterControls,
206
+ essentials: ["kind", "feeling", "body"],
207
+ // Variants step through the creatures in the generator, as the animals' are different animals.
208
+ styleKeys: ["feeling", "body"],
209
+ svg: critterSvg,
210
+ },
211
+ {
212
+ id: "grins",
213
+ label: "Grins",
214
+ group: "Illustrated",
215
+ hint: "A button of a face, a tile or round, with a big toothy grin. Its googly eyes follow you and blink, and it chomps when tapped",
216
+ defaultName: "Zuzu",
217
+ controls: grinControls,
218
+ essentials: ["eyes", "mouth", "body"],
219
+ styleKeys: ["eyes", "mouth", "body"],
220
+ svg: grinSvg,
221
+ },
222
+ {
223
+ id: "knits",
224
+ // Hidden for now, as asked. Its code stays as it was.
225
+ hidden: true,
226
+ label: "Knits",
227
+ group: "Illustrated",
228
+ hint: "A bust in a knitted balaclava and a ribbed beanie. Its eyes follow you and blink",
229
+ defaultName: "Kade",
230
+ controls: knitControls,
231
+ essentials: ["mood", "hat", "mask"],
232
+ styleKeys: ["mood", "mask", "clothes"],
233
+ svg: knitSvg,
234
+ },
235
+ {
236
+ id: "glances",
237
+ label: "Glances",
238
+ group: "Illustrated",
239
+ hint: "Just two eyes. They follow you, glance about and blink, and pop when tapped",
240
+ defaultName: "Nyx",
241
+ controls: glanceControls,
242
+ essentials: ["eye.left", "eye.right", "tile"],
243
+ styleKeys: ["eye.left", "eye.right", "tile"],
244
+ svg: glanceSvg,
245
+ },
246
+ {
247
+ id: "auras",
248
+ // No animation at all, as asked: no drift, cursor, hover or tap, and no Motion controls.
249
+ still: true,
250
+ label: "Auras",
251
+ group: "Illustrated",
252
+ hint: "Soft colour melting together under a fine grain, or a sky, on a rounded tile. It holds perfectly still",
253
+ defaultName: "Luma",
254
+ controls: auraControls,
255
+ // The type and a sky's horizon were asked for up front beside the rest, as the animals'
256
+ // type is. Formation is only an aura's and Horizon only a sky's, so it shows 7.
257
+ essentials: ["type", "flow", "palette", "face"],
258
+ // Variants step through the types, formations and palettes themselves, as Mallows do,
259
+ // since each type has palettes of its own. See `stepped` in auras/index.ts.
260
+ styleKeys: [],
261
+ svg: auraSvg,
262
+ },
263
+ ];
264
+ /** The kinds shown on the canvas, which leaves out any hidden for now. */
265
+ export const SHOWN = KINDS.filter((kind) => !kind.hidden);
266
+ export const toDataUri = (svg) => `data:image/svg+xml,${encodeURIComponent(svg)}`;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * What Possibilities calms on a cat. Low keeps to the eight mildest expressions, one for
3
+ * each variant, smooth fur and the reference's corner poses. Every ear stays, so the
4
+ * variants still differ in silhouette. Indices are into the lists in `index.ts`.
5
+ */
6
+ import type { Calming } from "../possibilities.ts";
7
+ export declare const CALMING: Calming;
8
+ export declare const NOTES: [string, string, string];
@@ -0,0 +1,19 @@
1
+ /**
2
+ * What Possibilities calms on a cat. Low keeps to the eight mildest expressions, one for
3
+ * each variant, smooth fur and the reference's corner poses. Every ear stays, so the
4
+ * variants still differ in silhouette. Indices are into the lists in `index.ts`.
5
+ */
6
+ export const CALMING = {
7
+ features: /^(head|eye|ear|whisker|lid|body)\.|^tilt$/,
8
+ lists: {
9
+ // Curious, Happy, Sleepy, Smug, Grumpy, Annoyed, Shocked, Hungry, then Sassy, Sly, Smitten, Menacing, Dizzy.
10
+ mood: [13, 8, [2, 4, 3, 1, 7, 0, 5, 8, 12, 6, 9, 10, 11]],
11
+ pose: [6, 2],
12
+ "fur.style": [3, 1],
13
+ },
14
+ };
15
+ export const NOTES = [
16
+ "mild moods like curious, happy and sleepy, with smooth fur, sitting in from the corner.",
17
+ "adds sassy and sly looks, fluffy and chubby cheeks, and more poses.",
18
+ "every expression, up to smitten, menacing and dizzy, in any pose.",
19
+ ];
@@ -0,0 +1,2 @@
1
+ import { type ControlBuilder } from "../controls.ts";
2
+ export declare const animalControls: ControlBuilder;
@@ -0,0 +1,43 @@
1
+ import { choice, fixedPalette, palette, slider } from "../controls.js";
2
+ import { calmed, narrowed, possibilitiesSlider } from "../possibilities.js";
3
+ import { createTraits } from "../traits.js";
4
+ import { CALMING, NOTES } from "./calming.js";
5
+ import { EARS, EYE_COLOURS, FUR_STYLES, FURS, MOODS, POSES, SPECIES, speciesOf, TILES, VIEWS } from "./index.js";
6
+ const named = (list) => list.map(({ name: label }) => ({ label }));
7
+ /** Cats, or Animals, which also picks the animal and hides what it doesn't have. */
8
+ const controlsFor = (animals) => (name, overrides) => {
9
+ const t = calmed(createTraits(name, overrides), CALMING);
10
+ const list = (control) => narrowed(control, t, CALMING);
11
+ const species = animals ? speciesOf(t) : SPECIES[0];
12
+ return [
13
+ {
14
+ title: "Face",
15
+ controls: [
16
+ list(choice(t, "mood", "Expression", "list", named(MOODS))),
17
+ possibilitiesSlider(t, NOTES),
18
+ fixedPalette(t, "eyes.color", "Eye colour", EYE_COLOURS),
19
+ slider(t, "eye.size", "Eye size", 0, 100, "%"),
20
+ slider(t, "eye.gap", "Eye gap", 0, 100, "%"),
21
+ ...(species.whiskers ? [slider(t, "whisker.length", "Whiskers", 0, 100, "%")] : []),
22
+ ],
23
+ },
24
+ {
25
+ title: animals ? "Animal" : "Cat",
26
+ controls: [
27
+ ...(animals ? [choice(t, "animal", "Animal", "list", named(SPECIES))] : []),
28
+ // The owl is drawn from its own reference, in one view.
29
+ ...(species.view ? [] : [choice(t, "view", "View", "list", named(VIEWS))]),
30
+ choice(t, "ears", "Ears", "list", named(EARS)),
31
+ list(choice(t, "pose", "Pose", "list", named(POSES))),
32
+ ...(species.cheeks ? [] : [list(choice(t, "fur.style", "Cheeks", "list", named(FUR_STYLES)))]),
33
+ slider(t, "head.width", "Head width", 0, 100, "%"),
34
+ slider(t, "tilt", "Tilt", -5, 5, "°"),
35
+ ],
36
+ },
37
+ {
38
+ title: "Colour",
39
+ controls: [palette(t, "tile", "Colour", TILES), fixedPalette(t, "fur", "Fur", FURS)],
40
+ },
41
+ ];
42
+ };
43
+ export const animalControls = controlsFor(true);
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Cats, traced from the reference: a black cat in three-quarter view, its head tipped and
3
+ * coming in from the corner. Its ears have rounded tips and edges that bulge a little, and
4
+ * a dark inner ear. Each eye is an ellipse cut straight across by the lid through its
5
+ * middle, so the corner by the nose is sharp and the outer end round, and the lid's angle
6
+ * is most of the mood. The nose sits off towards the far eye, and the mouth is a thick
7
+ * grey line, longer on the near side, with a single fang.
8
+ *
9
+ * There are two views, each traced from its own reference: turned three-quarters, and nearly
10
+ * face on with a pink nose and an open mouth. Points are in tile units, traced from 1200 px
11
+ * drawings at a twelfth of their size. The face is drawn upright about the nose, then turned
12
+ * with the head by the view's tilt.
13
+ */
14
+ import { type Overrides, type Traits } from "../traits.ts";
15
+ export declare const TILES: string[];
16
+ export declare const FURS: string[];
17
+ export declare const EYE_COLOURS: string[];
18
+ type Point = readonly [number, number];
19
+ interface Ear {
20
+ inner: Point;
21
+ tip: Point;
22
+ outer: Point;
23
+ }
24
+ /** One way of seeing the cat, each traced from its own reference. */
25
+ interface View {
26
+ name: string;
27
+ /** The middle of the head, which it grows about, and the nose, which the face hangs from. */
28
+ centre: Point;
29
+ nose: Point;
30
+ /** How far the face is tipped, and how big it is against the three-quarter one's. */
31
+ tilt: number;
32
+ /** Fits the traced drawing to the tile, before any pose. */
33
+ frame: string;
34
+ /** The head without its ears, clockwise from under the left ear, and which points are cheeks. */
35
+ head: Point[];
36
+ cheeks: number[];
37
+ body: Point[];
38
+ /** Each ear by where it meets the head and where its tip is. */
39
+ ears: [Ear, Ear];
40
+ /** Whiskers as root, bend and end, three a side. */
41
+ whiskers: Point[][];
42
+ /** The eyes in the face's frame, far then near. */
43
+ eyes: {
44
+ c: Point;
45
+ rx: number;
46
+ ry: number;
47
+ }[];
48
+ noseShape: string;
49
+ /** What the nose and the inside of the ears are tinted towards, and how far. */
50
+ noseTint: [string, number];
51
+ earTint: [string, number];
52
+ /** Grey whiskers all the way out, rather than fur over the tile. */
53
+ greyWhiskers?: boolean;
54
+ /** Pupils that hang as tall ovals, rather than circles. */
55
+ tallPupils?: boolean;
56
+ /** Pupils that look in towards the nose, a glare, rather than aside. */
57
+ pupilsIn?: boolean;
58
+ }
59
+ /** Neighbours are as unlike as possible, since each variant steps to the next. */
60
+ export declare const VIEWS: View[];
61
+ interface Pose {
62
+ name: string;
63
+ x: number;
64
+ y: number;
65
+ scale: number;
66
+ turn: number;
67
+ mirrored?: boolean;
68
+ }
69
+ /** The first is the reference, in from the corner. */
70
+ export declare const POSES: Pose[];
71
+ interface Ears {
72
+ name: string;
73
+ /** Length against the reference's, how far the tips lean out, and how round they are. */
74
+ height: number;
75
+ flare: number;
76
+ round: number;
77
+ notch?: boolean;
78
+ tuft?: boolean;
79
+ /** Short and folded forward, so the inside doesn't show. */
80
+ folded?: boolean;
81
+ /** One ear flopped out to the side. */
82
+ odd?: boolean;
83
+ }
84
+ /** Neighbours are as unlike as possible, since each variant steps to the next. */
85
+ export declare const EARS: Ears[];
86
+ /** Collars come in a few colours; the first is the reference's grey, taken from the fur. */
87
+ export declare const COLLARS: string[];
88
+ type EarKind = "point" | "tuft" | "round";
89
+ /**
90
+ * An animal, drawn in the cat's finish: flat fur, details in grey line, the same eyes. Each
91
+ * has its own anatomy, though, so none reads as a cat with other ears.
92
+ */
93
+ interface Species {
94
+ name: string;
95
+ /** Pointed like a cat's, a dog's or a tiger's, feather tufts like an owl's, or round like a bear's. */
96
+ ears: EarKind;
97
+ /** An owl has its discs, chest feathers and wing; a dog its muzzle and collar; a tiger its stripes. */
98
+ head?: "dog" | "owl" | "tiger";
99
+ /** How round the ear tips are at the least, and how far their edges bow out. */
100
+ earRound?: number;
101
+ earBulge?: number;
102
+ /** How far the inside of the ear is drawn in from its edge, for a wider border of fur. */
103
+ earInset?: number;
104
+ /** Cheeks it always has, rather than the name's. */
105
+ cheeks?: "Smooth" | "Fluffy" | "Chubby";
106
+ nose: "cat" | "dog" | "bear" | "beak" | "tiger";
107
+ whiskers?: boolean;
108
+ /** Shows the mood's fangs. */
109
+ fangs?: boolean;
110
+ /** Drawn from its own reference, rather than from the cat's views. */
111
+ view?: View;
112
+ }
113
+ /** The animals. Neighbours are as unlike as possible. */
114
+ export declare const SPECIES: Species[];
115
+ export declare const FUR_STYLES: {
116
+ name: string;
117
+ }[];
118
+ /** Open, shut, smiling shut, or cut by the lid at a slope towards the nose and a depth. */
119
+ type Lid = "open" | "closed" | "happy" | readonly [slope: number, depth: number];
120
+ type Pupil = "none" | "hang" | "big" | "tiny" | "slit" | "heart" | "cross";
121
+ interface Mood {
122
+ name: string;
123
+ lids: [Lid, Lid];
124
+ pupil: Pupil;
125
+ mouth: keyof typeof MOUTHS;
126
+ fangs?: 1 | 2;
127
+ }
128
+ /** Every expression. The first two are the references. */
129
+ export declare const MOODS: Mood[];
130
+ /** In the face's frame: the nose at 0 0, the near side to the right. */
131
+ declare const MOUTHS: {
132
+ none: string;
133
+ smirk: string;
134
+ w: string;
135
+ smile: string;
136
+ frown: string;
137
+ flat: string;
138
+ oh: string;
139
+ tongue: string;
140
+ open: string;
141
+ };
142
+ export declare const viewOf: (t: Traits) => View;
143
+ export declare const speciesOf: (t: Traits) => Species;
144
+ export declare const moodOf: (t: Traits) => Mood;
145
+ export declare const poseOf: (t: Traits) => Pose;
146
+ export declare const earsOf: (t: Traits) => Ears;
147
+ export declare const furStyleOf: (t: Traits) => {
148
+ name: string;
149
+ };
150
+ export declare function coloursOf(t: Traits): {
151
+ tile: string;
152
+ fur: string;
153
+ eye: string;
154
+ };
155
+ export interface Kitty {
156
+ /** Clip paths and the tile's grain, which the drawing refers to by id. */
157
+ defs: string;
158
+ tile: string;
159
+ pose: string;
160
+ mirrored: boolean;
161
+ /** Body, head, fluff and whiskers. */
162
+ body: string;
163
+ ears: [string, string];
164
+ /** Whether the ears are drawn over the head rather than behind it. */
165
+ earsFront: boolean;
166
+ /** Each eye, with its pupil marked so it can look about inside it. */
167
+ eyes: string;
168
+ face: string;
169
+ /** What sits round the eyes and keeps still while they blink: an owl's disc, a dog's brows. */
170
+ discs: string;
171
+ blinkDelay: number;
172
+ }
173
+ /** Cats draws only cats; Animals picks the animal too, with ids of its own so both can be on the page. */
174
+ export declare function createKitty(name: string, overrides?: Overrides, animals?: boolean, ids?: string): Kitty;
175
+ export declare const TILE_SHAPE = "<rect width=\"100\" height=\"100\" rx=\"22.22\"/>";
176
+ /** The id prefix each section's drawing uses. */
177
+ export declare const prefixOf: (animals: boolean) => "animal" | "kitty";
178
+ /** The tile and its grain, which sit still behind the animal. */
179
+ export declare const tileMarkup: (fill: string, ids: string) => string;
180
+ export declare const animalSvg: (name: string, overrides?: Overrides) => string;
181
+ export {};