@fungi.computer/sprite-zdog 0.0.0-stage → 0.0.1

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 (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +125 -2
  3. package/dist/agent-proof/moth.d.ts +50 -0
  4. package/dist/agent-proof/moth.js +52 -0
  5. package/dist/author.d.ts +217 -0
  6. package/dist/author.js +372 -0
  7. package/dist/avatar.d.ts +69 -0
  8. package/dist/avatar.js +40 -0
  9. package/dist/builtins/base-face.d.ts +290 -0
  10. package/dist/builtins/base-face.js +615 -0
  11. package/dist/builtins/base.d.ts +331 -0
  12. package/dist/builtins/base.js +579 -0
  13. package/dist/builtins/burger-input.d.ts +310 -0
  14. package/dist/builtins/burger-input.js +517 -0
  15. package/dist/builtins/burger.d.ts +305 -0
  16. package/dist/builtins/burger.js +4 -0
  17. package/dist/builtins/cat-input.d.ts +316 -0
  18. package/dist/builtins/cat-input.js +255 -0
  19. package/dist/builtins/cat.d.ts +311 -0
  20. package/dist/builtins/cat.js +4 -0
  21. package/dist/builtins/index.d.ts +4 -0
  22. package/dist/builtins/index.js +4 -0
  23. package/dist/builtins/mushroom-input.d.ts +314 -0
  24. package/dist/builtins/mushroom-input.js +94 -0
  25. package/dist/builtins/mushroom.d.ts +310 -0
  26. package/dist/builtins/mushroom.js +4 -0
  27. package/dist/burger.d.ts +9 -0
  28. package/dist/burger.js +15 -0
  29. package/dist/cat.d.ts +9 -0
  30. package/dist/cat.js +15 -0
  31. package/dist/catalog.d.ts +3 -0
  32. package/dist/catalog.js +63 -0
  33. package/dist/document.d.ts +444 -0
  34. package/dist/document.js +204 -0
  35. package/dist/index.d.ts +10 -0
  36. package/dist/index.js +10 -0
  37. package/dist/internal.d.ts +41 -0
  38. package/dist/internal.js +21 -0
  39. package/dist/mushroom.character.json +1930 -0
  40. package/dist/mushroom.d.ts +4 -0
  41. package/dist/mushroom.js +9 -0
  42. package/dist/palette.d.ts +3 -0
  43. package/dist/palette.js +5 -0
  44. package/dist/portable.d.ts +4 -0
  45. package/dist/portable.js +61 -0
  46. package/dist/renderer.d.ts +4 -0
  47. package/dist/renderer.js +106 -0
  48. package/dist/zdog-runtime.d.ts +21 -0
  49. package/dist/zdog-runtime.js +622 -0
  50. package/package.json +112 -3
@@ -0,0 +1,615 @@
1
+ /**
2
+ * The shared face language used by the legacy ball, mushroom, cat and burger.
3
+ * This is deliberately written against the public scene builder rather than
4
+ * sharing renderer objects between definitions.
5
+ */
6
+ export const buildBaseFace = (scene, color, parent, options = {}) => {
7
+ const eyesParent = scene.group({ parent, name: "eyes" });
8
+ const mouthOptions = { parent, name: "mouth" };
9
+ if (options.mouthTranslate !== undefined)
10
+ Object.assign(mouthOptions, { translate: options.mouthTranslate });
11
+ const mouthParent = options.hideMouth ? undefined : scene.group(mouthOptions);
12
+ const ellipseEyes = (name, width, height, y, rotate, highlightWidth, highlightHeight) => {
13
+ const group = scene.group({ parent: eyesParent, name: `eyes.${name}` });
14
+ for (const side of [-1, 1]) {
15
+ const eyeOptions = { parent: group, translate: { x: 6 * side, y } };
16
+ if (rotate)
17
+ Object.assign(eyeOptions, { rotate: { z: rotate * side } });
18
+ const eye = scene.group(eyeOptions);
19
+ scene.ellipse({
20
+ parent: eye,
21
+ width,
22
+ height,
23
+ stroke: 1.5,
24
+ fill: true,
25
+ color: color("eye"),
26
+ });
27
+ scene.ellipse({
28
+ parent: eye,
29
+ width: highlightWidth,
30
+ height: highlightHeight,
31
+ stroke: 0.5,
32
+ fill: true,
33
+ color: color("white"),
34
+ translate: { y: -highlightHeight / 2, z: 1 },
35
+ });
36
+ }
37
+ return group;
38
+ };
39
+ const neutralEyes = {
40
+ normal: ellipseEyes("normal", 3, 5, -2, 0, 1.5, 2),
41
+ sad: ellipseEyes("sad", 3, 4, -1, -0.2, 1.5, 2),
42
+ surprised: ellipseEyes("surprised", 4, 5, -2, 0, 1.5, 2),
43
+ };
44
+ const happy = scene.group({ parent: eyesParent, name: "eyes.happy" });
45
+ for (const side of [-1, 1]) {
46
+ scene.path({
47
+ parent: happy,
48
+ path: [
49
+ { x: -2.5, y: 2 },
50
+ {
51
+ bezier: [
52
+ { x: -1, y: -1.5 },
53
+ { x: 1, y: -1.5 },
54
+ { x: 2.5, y: 2 },
55
+ ],
56
+ },
57
+ ],
58
+ closed: false,
59
+ stroke: 1.5,
60
+ color: color("eye"),
61
+ translate: { x: 6 * side, y: -2 },
62
+ });
63
+ }
64
+ const angry = scene.group({ parent: eyesParent, name: "eyes.angry" });
65
+ for (const side of [-1, 1]) {
66
+ const eye = scene.group({
67
+ parent: angry,
68
+ rotate: { z: 0.3 * side },
69
+ translate: { x: 6 * side, y: -1 },
70
+ });
71
+ scene.ellipse({
72
+ parent: eye,
73
+ width: 3,
74
+ height: 4,
75
+ stroke: 1.5,
76
+ fill: true,
77
+ color: color("eye"),
78
+ });
79
+ scene.path({
80
+ parent: eye,
81
+ path: [
82
+ { x: -3, y: -3 },
83
+ { x: 3, y: -2 },
84
+ ],
85
+ stroke: 1.5,
86
+ color: color("eye"),
87
+ translate: { y: -1 },
88
+ });
89
+ }
90
+ const dead = scene.group({ parent: eyesParent, name: "eyes.dead" });
91
+ for (const side of [-1, 1]) {
92
+ const eye = scene.group({
93
+ parent: dead,
94
+ translate: { x: 6 * side, y: -2 },
95
+ });
96
+ scene.path({
97
+ parent: eye,
98
+ path: [
99
+ { x: -2, y: -3 },
100
+ { x: 2, y: 3 },
101
+ ],
102
+ stroke: 1.5,
103
+ color: color("dead"),
104
+ });
105
+ scene.path({
106
+ parent: eye,
107
+ path: [
108
+ { x: 2, y: -3 },
109
+ { x: -2, y: 3 },
110
+ ],
111
+ stroke: 1.5,
112
+ color: color("dead"),
113
+ });
114
+ }
115
+ const confused = scene.group({ parent: eyesParent, name: "eyes.confused" });
116
+ const confusedLeft = scene.group({
117
+ parent: confused,
118
+ translate: { x: -6, y: -2 },
119
+ });
120
+ scene.ellipse({
121
+ parent: confusedLeft,
122
+ width: 3,
123
+ height: 5,
124
+ stroke: 1.5,
125
+ fill: true,
126
+ color: color("eye"),
127
+ });
128
+ scene.path({
129
+ parent: confusedLeft,
130
+ path: [
131
+ { x: -3, y: -4 },
132
+ { x: 3, y: -2 },
133
+ ],
134
+ stroke: 1.5,
135
+ color: color("eye"),
136
+ });
137
+ const confusedRight = scene.group({
138
+ parent: confused,
139
+ translate: { x: 6, y: -2 },
140
+ });
141
+ scene.ellipse({
142
+ parent: confusedRight,
143
+ width: 3,
144
+ height: 5,
145
+ stroke: 1.5,
146
+ fill: true,
147
+ color: color("eye"),
148
+ });
149
+ const sleepy = scene.group({ parent: eyesParent, name: "eyes.sleepy" });
150
+ for (const side of [-1, 1]) {
151
+ scene.path({
152
+ parent: sleepy,
153
+ path: [
154
+ { x: -2.5, y: 1 },
155
+ {
156
+ bezier: [
157
+ { x: -1, y: 0 },
158
+ { x: 1, y: 0 },
159
+ { x: 2.5, y: 1 },
160
+ ],
161
+ },
162
+ ],
163
+ closed: false,
164
+ stroke: 1.5,
165
+ color: color("eye"),
166
+ translate: { x: 6 * side, y: -1 },
167
+ });
168
+ }
169
+ const nervous = scene.group({ parent: eyesParent, name: "eyes.nervous" });
170
+ for (const side of [-1, 1]) {
171
+ const eye = scene.group({
172
+ parent: nervous,
173
+ translate: { x: 6 * side, y: -2 },
174
+ });
175
+ scene.ellipse({
176
+ parent: eye,
177
+ width: 3,
178
+ height: 5,
179
+ stroke: 1.5,
180
+ fill: true,
181
+ color: color("eye"),
182
+ });
183
+ }
184
+ const sweat = scene.group({ parent: nervous, translate: { x: 10, y: 4 } });
185
+ scene.path({
186
+ parent: sweat,
187
+ path: [{ x: 0, y: -4 }],
188
+ stroke: 2,
189
+ color: color("sweat"),
190
+ });
191
+ scene.ellipse({
192
+ parent: sweat,
193
+ width: 3,
194
+ height: 4,
195
+ stroke: 0,
196
+ fill: true,
197
+ color: color("sweat"),
198
+ translate: { y: 2 },
199
+ });
200
+ const shy = scene.group({ parent: eyesParent, name: "eyes.shy" });
201
+ for (const side of [-1, 1])
202
+ scene.ellipse({
203
+ parent: shy,
204
+ width: 2.5,
205
+ height: 2,
206
+ stroke: 1.5,
207
+ fill: true,
208
+ color: color("eye"),
209
+ translate: { x: 6 * side, y: -2 },
210
+ });
211
+ const cute = scene.group({ parent: eyesParent, name: "eyes.cute" });
212
+ for (const side of [-1, 1]) {
213
+ const eye = scene.group({
214
+ parent: cute,
215
+ translate: { x: 6 * side, y: -1 },
216
+ });
217
+ scene.ellipse({
218
+ parent: eye,
219
+ width: 5,
220
+ height: 6,
221
+ stroke: 1.5,
222
+ fill: true,
223
+ color: color("eye"),
224
+ });
225
+ scene.ellipse({
226
+ parent: eye,
227
+ width: 2.5,
228
+ height: 3,
229
+ stroke: 0,
230
+ fill: true,
231
+ color: color("white"),
232
+ translate: { y: -1.5, z: 1 },
233
+ });
234
+ scene.ellipse({
235
+ parent: eye,
236
+ width: 1,
237
+ height: 1,
238
+ stroke: 0,
239
+ fill: true,
240
+ color: color("white"),
241
+ translate: { x: -1.5, y: 1.5, z: 1 },
242
+ });
243
+ }
244
+ // A wink closes one eye and keeps the other open: each choice draws both.
245
+ const wink = scene.group({ parent: eyesParent, name: "eyes.wink" });
246
+ const winkEyes = (side) => {
247
+ const group = scene.group({ parent: wink, name: `eyes.wink.${side}` });
248
+ const closed = side === "left" ? -1 : 1;
249
+ scene.path({
250
+ parent: group,
251
+ path: [
252
+ { x: -2.5, y: 2 },
253
+ {
254
+ bezier: [
255
+ { x: -1, y: -1.5 },
256
+ { x: 1, y: -1.5 },
257
+ { x: 2.5, y: 2 },
258
+ ],
259
+ },
260
+ ],
261
+ closed: false,
262
+ stroke: 1.5,
263
+ color: color("eye"),
264
+ translate: { x: 6 * closed, y: -2 },
265
+ });
266
+ scene.ellipse({
267
+ parent: group,
268
+ width: 3,
269
+ height: 5,
270
+ stroke: 1.5,
271
+ fill: true,
272
+ color: color("eye"),
273
+ translate: { x: -6 * closed, y: -2 },
274
+ });
275
+ return group;
276
+ };
277
+ const winkLeft = winkEyes("left");
278
+ const winkRight = winkEyes("right");
279
+ const mouths = (() => {
280
+ if (!mouthParent)
281
+ return {};
282
+ const mouth = (name, path, stroke = 1.5) => scene.path({
283
+ parent: mouthParent,
284
+ name: `mouth.${name}`,
285
+ path,
286
+ closed: false,
287
+ stroke,
288
+ color: color("mouth"),
289
+ translate: { y: 2 },
290
+ });
291
+ const resting = {
292
+ normal: mouth("normal", [
293
+ { x: -2.5, y: 0 },
294
+ { x: 2.5, y: 0 },
295
+ ]),
296
+ happy: mouth("happy", [
297
+ { x: -2.5, y: 2 },
298
+ {
299
+ bezier: [
300
+ { x: 0, y: 4 },
301
+ { x: 2.5, y: 2 },
302
+ { x: 2.5, y: 2 },
303
+ ],
304
+ },
305
+ ]),
306
+ sad: mouth("sad", [
307
+ { x: -2.5, y: 2 },
308
+ {
309
+ bezier: [
310
+ { x: 0, y: 0 },
311
+ { x: 2.5, y: 2 },
312
+ { x: 2.5, y: 2 },
313
+ ],
314
+ },
315
+ ]),
316
+ small: mouth("small", [
317
+ { x: -1.5, y: 0 },
318
+ { x: 1.5, y: 0 },
319
+ ], 1),
320
+ worried: mouth("worried", [
321
+ { x: -2, y: 1 },
322
+ {
323
+ bezier: [
324
+ { x: -0.5, y: 0.5 },
325
+ { x: 0.5, y: 0.5 },
326
+ { x: 2, y: 1 },
327
+ ],
328
+ },
329
+ ], 1),
330
+ };
331
+ const pout = scene.ellipse({
332
+ parent: mouthParent,
333
+ name: "mouth.pout",
334
+ width: 2,
335
+ height: 2.5,
336
+ stroke: 1.5,
337
+ fill: true,
338
+ color: color("mouth"),
339
+ translate: { y: 3 },
340
+ });
341
+ const surprised = scene.ellipse({
342
+ parent: mouthParent,
343
+ name: "mouth.surprised",
344
+ width: 3,
345
+ height: 4,
346
+ stroke: 1.5,
347
+ fill: true,
348
+ color: color("mouth"),
349
+ translate: { y: 3 },
350
+ });
351
+ const deadMouth = scene.group({
352
+ parent: mouthParent,
353
+ name: "mouth.dead",
354
+ translate: { y: 5 },
355
+ });
356
+ scene.ellipse({
357
+ parent: deadMouth,
358
+ width: 3,
359
+ height: 2,
360
+ stroke: 1.5,
361
+ fill: true,
362
+ color: color("dead"),
363
+ });
364
+ scene.ellipse({
365
+ parent: deadMouth,
366
+ width: 1.5,
367
+ height: 1,
368
+ stroke: 0,
369
+ fill: true,
370
+ color: color("deadTongue"),
371
+ translate: { y: 0.5 },
372
+ });
373
+ const openMouth = scene.group({
374
+ parent: mouthParent,
375
+ name: "mouth.open",
376
+ translate: { y: 2 },
377
+ });
378
+ scene.ellipse({
379
+ parent: openMouth,
380
+ width: 6,
381
+ height: 4,
382
+ stroke: 1.5,
383
+ fill: true,
384
+ color: color("mouth"),
385
+ });
386
+ scene.ellipse({
387
+ parent: openMouth,
388
+ name: "mouth.tongue",
389
+ width: 3,
390
+ height: 1.5,
391
+ stroke: 0,
392
+ fill: true,
393
+ color: color("tongue"),
394
+ translate: { y: 1 },
395
+ });
396
+ return {
397
+ normal: resting.normal,
398
+ happy: resting.happy,
399
+ sad: resting.sad,
400
+ angry: resting.sad,
401
+ surprised,
402
+ dead: deadMouth,
403
+ small: resting.small,
404
+ worried: resting.worried,
405
+ pout,
406
+ open: openMouth,
407
+ };
408
+ })();
409
+ const blush = (name, width, height, stroke, x) => {
410
+ const group = scene.group({ parent, name: `blush.${name}` });
411
+ for (const side of [-1, 1])
412
+ scene.ellipse({
413
+ parent: group,
414
+ width,
415
+ height,
416
+ stroke,
417
+ fill: true,
418
+ color: color("blush"),
419
+ translate: { x: x * side, y: 4 },
420
+ });
421
+ return group;
422
+ };
423
+ const blushOff = scene.group({ parent, name: "blush.off" });
424
+ // Mushroom and burger inherit one legacy medium blush node for all
425
+ // intensities. Its stroke is part of their geometry contract.
426
+ const blushMedium = blush("medium", 5, 2.5, 1, 10);
427
+ const blushVariants = options.blushMode === "medium-alias"
428
+ ? {
429
+ off: blushOff,
430
+ small: blushMedium,
431
+ medium: blushMedium,
432
+ big: blushMedium,
433
+ }
434
+ : {
435
+ off: blushOff,
436
+ small: blush("small", 3.5, 1.8, 1, 9),
437
+ medium: blushMedium,
438
+ big: blush("big", 7, 3.5, 2, 11),
439
+ };
440
+ const orderedEyes = {
441
+ normal: neutralEyes.normal,
442
+ happy,
443
+ sad: neutralEyes.sad,
444
+ angry,
445
+ surprised: neutralEyes.surprised,
446
+ dead,
447
+ confused,
448
+ sleepy,
449
+ nervous,
450
+ shy,
451
+ wink: winkLeft,
452
+ cute,
453
+ "wink.left": winkLeft,
454
+ "wink.right": winkRight,
455
+ };
456
+ return { eyes: orderedEyes, mouth: mouths, blush: blushVariants };
457
+ };
458
+ export const baseExpressions = {
459
+ angry: {
460
+ variants: { eyes: "angry", mouth: "angry", blush: "off" },
461
+ motion: {
462
+ target: "root",
463
+ translate: { x: 1, y: 0 },
464
+ durationMs: 150,
465
+ repeat: "none",
466
+ },
467
+ },
468
+ confused: {
469
+ variants: { eyes: "confused", mouth: "normal", blush: "off" },
470
+ motion: {
471
+ target: "root",
472
+ translate: { x: 0, y: 0.5 },
473
+ durationMs: 150,
474
+ repeat: "none",
475
+ },
476
+ },
477
+ cute: {
478
+ variants: { eyes: "cute", mouth: "happy", blush: "big" },
479
+ motion: {
480
+ target: "root",
481
+ translate: { x: 0, y: -2.5 },
482
+ durationMs: 150,
483
+ repeat: "none",
484
+ },
485
+ },
486
+ dead: { variants: { eyes: "dead", mouth: "dead", blush: "off" } },
487
+ happy: {
488
+ variants: { eyes: "happy", mouth: "happy", blush: "medium" },
489
+ motion: {
490
+ target: "root",
491
+ translate: { x: 0, y: -2 },
492
+ durationMs: 150,
493
+ repeat: "none",
494
+ },
495
+ },
496
+ nervous: {
497
+ variants: { eyes: "nervous", mouth: "worried", blush: "off" },
498
+ motion: {
499
+ target: "root",
500
+ translate: { x: -0.5, y: -1 },
501
+ durationMs: 150,
502
+ repeat: "none",
503
+ },
504
+ },
505
+ normal: {
506
+ variants: { eyes: "normal", mouth: "normal", blush: "off" },
507
+ motion: {
508
+ target: "root",
509
+ translate: { x: 0, y: 1 },
510
+ durationMs: 150,
511
+ repeat: "none",
512
+ },
513
+ },
514
+ pleading: {
515
+ variants: { eyes: "cute", mouth: "pout", blush: "medium" },
516
+ motion: {
517
+ target: "root",
518
+ translate: { x: 0, y: -1 },
519
+ durationMs: 150,
520
+ repeat: "none",
521
+ },
522
+ },
523
+ sad: {
524
+ variants: { eyes: "sad", mouth: "sad", blush: "off" },
525
+ motion: {
526
+ target: "root",
527
+ translate: { x: 0, y: 2 },
528
+ durationMs: 150,
529
+ repeat: "none",
530
+ },
531
+ },
532
+ shy: {
533
+ variants: { eyes: "shy", mouth: "small", blush: "small" },
534
+ motion: {
535
+ target: "root",
536
+ translate: { x: 0, y: 1.5 },
537
+ durationMs: 150,
538
+ repeat: "none",
539
+ },
540
+ },
541
+ sleepy: {
542
+ variants: { eyes: "sleepy", mouth: "small", blush: "off" },
543
+ motion: {
544
+ target: "root",
545
+ translate: { x: 0, y: 2 },
546
+ durationMs: 150,
547
+ repeat: "none",
548
+ },
549
+ },
550
+ surprised: {
551
+ variants: { eyes: "surprised", mouth: "surprised", blush: "off" },
552
+ motion: {
553
+ target: "root",
554
+ translate: { x: 0, y: -3 },
555
+ durationMs: 150,
556
+ repeat: "none",
557
+ },
558
+ },
559
+ wink: {
560
+ variants: { mouth: "happy", blush: "small" },
561
+ variantChoices: { eyes: ["wink.left", "wink.right"] },
562
+ motion: {
563
+ target: "root",
564
+ translate: { x: 0, y: -1.5 },
565
+ durationMs: 150,
566
+ repeat: "none",
567
+ },
568
+ },
569
+ };
570
+ export const baseActivities = {
571
+ idle: {
572
+ motion: {
573
+ target: "root",
574
+ translate: { y: 0.5 },
575
+ durationMs: 2000,
576
+ repeat: "yoyo",
577
+ },
578
+ mouseInfluence: 1,
579
+ },
580
+ listening: {
581
+ motion: {
582
+ target: "root",
583
+ rotate: { x: -0.2 },
584
+ durationMs: 300,
585
+ repeat: "yoyo",
586
+ },
587
+ mouseInfluence: 0.3,
588
+ },
589
+ processing: { mouseInfluence: 0.2 },
590
+ speaking: {
591
+ motion: {
592
+ target: "root",
593
+ translate: { y: 0.5 },
594
+ durationMs: 1500,
595
+ repeat: "yoyo",
596
+ },
597
+ mouseInfluence: 0,
598
+ mouthCycle: [
599
+ { durationMs: 100, mouth: "open" },
600
+ { durationMs: 150, mouth: "base" },
601
+ { durationMs: 100, mouth: "open" },
602
+ { durationMs: 200, mouth: "base" },
603
+ ],
604
+ },
605
+ thinking: {
606
+ motion: {
607
+ target: "root",
608
+ rotate: { z: 0.1 },
609
+ durationMs: 800,
610
+ repeat: "yoyo",
611
+ },
612
+ mouseInfluence: 0,
613
+ },
614
+ error: { geometry: { expression: "dead" }, mouseInfluence: 0.1 },
615
+ };