desktop-pet-app 0.1.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.
@@ -0,0 +1,1661 @@
1
+ function decideBehavior() {
2
+ const r = Math.random();
3
+ if (r < 0.5) return { state: "idle", duration: 5 + Math.floor(Math.random() * 8) };
4
+ if (r < 0.85) {
5
+ return {
6
+ state: "walk",
7
+ duration: 4 + Math.floor(Math.random() * 8),
8
+ dir: Math.random() < 0.5 ? 1 : -1
9
+ };
10
+ }
11
+ return { state: "sleep", duration: 10 + Math.floor(Math.random() * 12) };
12
+ }
13
+ const WALK_SPEED = 5;
14
+ class Animator {
15
+ constructor(getSkin) {
16
+ this.getSkin = getSkin;
17
+ }
18
+ state = "idle";
19
+ blink = false;
20
+ tickCount = 0;
21
+ reaction = null;
22
+ ticks = 0;
23
+ duration = 6;
24
+ overrideTicks = 0;
25
+ reactionTicks = 0;
26
+ walkDir = 1;
27
+ /** 走路时每 tick 的位移回调(由 pet-view 转发给主进程移动窗口) */
28
+ onMove = () => {
29
+ };
30
+ get frame() {
31
+ const f = this.getSkin().frames;
32
+ switch (this.state) {
33
+ case "walk":
34
+ return f.walk[this.tickCount % f.walk.length];
35
+ case "sleep":
36
+ return f.sleep[0];
37
+ case "excited":
38
+ return f.excited[this.tickCount % f.excited.length];
39
+ case "drag":
40
+ return f.drag[0];
41
+ case "working":
42
+ return f.working[this.tickCount % f.working.length];
43
+ case "success":
44
+ return f.success[this.tickCount % f.success.length];
45
+ case "failed":
46
+ return f.failed[this.tickCount % f.failed.length];
47
+ default:
48
+ return f.idle[0];
49
+ }
50
+ }
51
+ get flip() {
52
+ return this.state === "walk" && this.walkDir < 0;
53
+ }
54
+ advance() {
55
+ this.tickCount++;
56
+ if (this.reactionTicks > 0) {
57
+ this.reactionTicks--;
58
+ if (this.reactionTicks === 0) this.reaction = null;
59
+ }
60
+ if (this.state === "drag") return;
61
+ if (this.overrideTicks > 0) {
62
+ this.overrideTicks--;
63
+ if (this.overrideTicks === 0) this.adopt(decideBehavior());
64
+ } else {
65
+ this.ticks++;
66
+ if (this.ticks >= this.duration) this.adopt(decideBehavior());
67
+ }
68
+ this.blink = this.state === "idle" && (this.blink ? Math.random() < 0.4 : Math.random() < 0.15);
69
+ if (this.state === "walk") this.onMove(this.walkDir * WALK_SPEED, 0);
70
+ }
71
+ /** 外部事件强制进入某状态,持续 ttl 个 tick 后回归自主行为 */
72
+ forceState(state, ttl = 8, dir) {
73
+ this.state = state;
74
+ this.ticks = 0;
75
+ this.overrideTicks = ttl;
76
+ if (dir) this.walkDir = dir;
77
+ }
78
+ /** 播放互动特效(如爱心),持续 ttl 个 tick */
79
+ react(kind, ttl = 6) {
80
+ this.reaction = kind;
81
+ this.reactionTicks = ttl;
82
+ }
83
+ setDragging(dragging2) {
84
+ if (dragging2) {
85
+ this.state = "drag";
86
+ this.overrideTicks = 0;
87
+ } else {
88
+ this.forceState("excited", 2);
89
+ }
90
+ }
91
+ adopt(d) {
92
+ this.state = d.state;
93
+ this.ticks = 0;
94
+ this.duration = d.duration;
95
+ if (d.dir) this.walkDir = d.dir;
96
+ }
97
+ }
98
+ const SCALE = 7;
99
+ const COLS = 16;
100
+ const ROWS = 13;
101
+ const PIXEL_CANVAS_WIDTH = COLS * SCALE;
102
+ const PIXEL_CANVAS_HEIGHT = ROWS * SCALE;
103
+ const HEART$1 = [".X.X.", "XXXXX", "XXXXX", ".XXX.", "..X.."];
104
+ class PixelRenderer {
105
+ constructor(canvas2) {
106
+ this.canvas = canvas2;
107
+ canvas2.width = COLS * SCALE;
108
+ canvas2.height = ROWS * SCALE;
109
+ this.ctx = canvas2.getContext("2d");
110
+ }
111
+ ctx;
112
+ draw(skin, frame, opts = {}) {
113
+ const { blink = false, flip = false, sleeping = false, tick = 0, hearts = false } = opts;
114
+ const { ctx } = this;
115
+ const w = this.canvas.width;
116
+ const h = this.canvas.height;
117
+ ctx.clearRect(0, 0, w, h);
118
+ ctx.fillStyle = "rgba(0, 0, 0, 0.18)";
119
+ ctx.beginPath();
120
+ ctx.ellipse(w / 2, h - 4, 30, 5, 0, 0, Math.PI * 2);
121
+ ctx.fill();
122
+ ctx.save();
123
+ if (flip) {
124
+ ctx.translate(w, 0);
125
+ ctx.scale(-1, 1);
126
+ }
127
+ for (let y = 0; y < frame.length; y++) {
128
+ const row = frame[y];
129
+ for (let x = 0; x < row.length; x++) {
130
+ let ch = row[x];
131
+ if (ch === ".") continue;
132
+ if (blink && ch === "E") ch = "e";
133
+ const color = skin.palette[ch];
134
+ if (!color) continue;
135
+ ctx.fillStyle = color;
136
+ ctx.fillRect(x * SCALE, y * SCALE, SCALE, SCALE);
137
+ }
138
+ }
139
+ ctx.restore();
140
+ if (hearts) {
141
+ const rise = tick % 3 * 3;
142
+ ctx.fillStyle = "#FF6B6B";
143
+ this.drawHeart(ctx, w - 34, 18 - rise);
144
+ this.drawHeart(ctx, 18, 26 - rise);
145
+ }
146
+ if (sleeping) {
147
+ const off = tick % 3 * 4;
148
+ ctx.fillStyle = "rgba(45, 45, 45, 0.75)";
149
+ ctx.font = "bold 12px monospace";
150
+ ctx.fillText("z", w - 26, 28 - off);
151
+ ctx.font = "bold 16px monospace";
152
+ ctx.fillText("Z", w - 16, 16 - off);
153
+ }
154
+ }
155
+ drawHeart(ctx, px, py) {
156
+ for (let y = 0; y < HEART$1.length; y++) {
157
+ for (let x = 0; x < HEART$1[y].length; x++) {
158
+ if (HEART$1[y][x] === "X") ctx.fillRect(px + x * 2, py + y * 2, 2, 2);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ const SPRITE_SCALE = 0.7;
164
+ const HEART = [".X.X.", "XXXXX", "XXXXX", ".XXX.", "..X.."];
165
+ class SpriteRenderer {
166
+ constructor(canvas2, onReady) {
167
+ this.canvas = canvas2;
168
+ this.onReady = onReady;
169
+ this.ctx = canvas2.getContext("2d");
170
+ }
171
+ ctx;
172
+ img = new Image();
173
+ ready = false;
174
+ load(skin) {
175
+ this.ready = false;
176
+ this.canvas.width = skin.displaySize?.width ?? Math.round(skin.frameWidth * SPRITE_SCALE);
177
+ this.canvas.height = skin.displaySize?.height ?? Math.round(skin.frameHeight * SPRITE_SCALE);
178
+ this.img.onload = () => {
179
+ this.ready = true;
180
+ this.onReady();
181
+ };
182
+ this.img.src = skin.image;
183
+ }
184
+ draw(skin, state, elapsedMs, opts = {}) {
185
+ const { flip = false, sleeping = false, tick = 0, hearts = false } = opts;
186
+ const { ctx } = this;
187
+ const w = this.canvas.width;
188
+ const h = this.canvas.height;
189
+ ctx.clearRect(0, 0, w, h);
190
+ if (!this.ready) return;
191
+ const s = skin.states[state] ?? skin.states.idle;
192
+ const frame = Math.floor(elapsedMs / s.frameMs) % s.frames;
193
+ const motion = proceduralMotion(state, elapsedMs);
194
+ ctx.save();
195
+ ctx.translate(w / 2, h);
196
+ ctx.translate(motion.x, motion.y);
197
+ ctx.rotate(motion.rotation);
198
+ ctx.scale(motion.scaleX, motion.scaleY);
199
+ ctx.translate(-w / 2, -h);
200
+ if (flip) {
201
+ ctx.translate(w, 0);
202
+ ctx.scale(-1, 1);
203
+ }
204
+ ctx.imageSmoothingEnabled = skin.smoothing ?? true;
205
+ const sx = skin.imageLayout === "single" ? 0 : frame * skin.frameWidth;
206
+ const sy = skin.imageLayout === "single" ? 0 : s.row * skin.frameHeight;
207
+ ctx.drawImage(
208
+ this.img,
209
+ sx,
210
+ sy,
211
+ skin.frameWidth,
212
+ skin.frameHeight,
213
+ 0,
214
+ 0,
215
+ w,
216
+ h
217
+ );
218
+ ctx.restore();
219
+ if (hearts) {
220
+ const rise = tick % 3 * 3;
221
+ ctx.fillStyle = "#FF6B6B";
222
+ this.drawHeart(ctx, w - 34, 18 - rise);
223
+ this.drawHeart(ctx, 18, 26 - rise);
224
+ }
225
+ if (sleeping) {
226
+ const off = tick % 3 * 4;
227
+ ctx.fillStyle = "rgba(45, 45, 45, 0.75)";
228
+ ctx.font = "bold 12px monospace";
229
+ ctx.fillText("z", w - 26, 28 - off);
230
+ ctx.font = "bold 16px monospace";
231
+ ctx.fillText("Z", w - 16, 16 - off);
232
+ }
233
+ }
234
+ drawHeart(ctx, px, py) {
235
+ for (let y = 0; y < HEART.length; y++) {
236
+ for (let x = 0; x < HEART[y].length; x++) {
237
+ if (HEART[y][x] === "X") ctx.fillRect(px + x * 2, py + y * 2, 2, 2);
238
+ }
239
+ }
240
+ }
241
+ }
242
+ function proceduralMotion(state, elapsedMs) {
243
+ const wave = Math.sin(elapsedMs / 240);
244
+ switch (state) {
245
+ case "walk":
246
+ return { x: wave * 2, y: -Math.abs(wave) * 5, rotation: wave * 0.025, scaleX: 1, scaleY: 1 };
247
+ case "sleep":
248
+ return { x: 0, y: 3, rotation: -0.025, scaleX: 1.03, scaleY: 0.94 + wave * 0.015 };
249
+ case "excited":
250
+ case "success":
251
+ return { x: 0, y: -Math.abs(wave) * 10, rotation: wave * 0.03, scaleX: 1.03, scaleY: 1.03 };
252
+ case "drag":
253
+ return { x: wave * 3, y: -8, rotation: wave * 0.07, scaleX: 1, scaleY: 1 };
254
+ case "working":
255
+ return { x: 0, y: wave * 2, rotation: 0, scaleX: 1 + wave * 8e-3, scaleY: 1 - wave * 8e-3 };
256
+ case "failed":
257
+ return { x: 0, y: 5, rotation: -0.035, scaleX: 1.01, scaleY: 0.97 };
258
+ default:
259
+ return { x: 0, y: wave * 2, rotation: 0, scaleX: 1, scaleY: 1 + wave * 8e-3 };
260
+ }
261
+ }
262
+ const IDLE$9 = [
263
+ "................",
264
+ ".......dd.......",
265
+ "......daad......",
266
+ ".....daaaad.....",
267
+ "....daaaaaad....",
268
+ "...dEaaaaaEad...",
269
+ "...daabbbaad....",
270
+ "..gdaawwwwaadg..",
271
+ "..daawwwwwwaad..",
272
+ "...daawwwwaad...",
273
+ "....dddddddd....",
274
+ ".....dd..dd.....",
275
+ "......f..f......"
276
+ ];
277
+ const WALK_0$9 = [...IDLE$9];
278
+ const WALK_1$9 = [...IDLE$9.slice(0, 12), ".....f....f....."];
279
+ const SLEEP$9 = [...IDLE$9.slice(0, 5), "...deaaaaaead...", ...IDLE$9.slice(6)];
280
+ const EXCITED_0$9 = [
281
+ ...IDLE$9.slice(0, 5),
282
+ "...d*aaaaa*ad...",
283
+ ...IDLE$9.slice(6)
284
+ ];
285
+ const EXCITED_1$9 = [
286
+ ...IDLE$9.slice(0, 4),
287
+ "...gaaaaaaag....",
288
+ "...d*aaaaa*ad...",
289
+ ...IDLE$9.slice(6, 12),
290
+ ".....f....f....."
291
+ ];
292
+ const DRAG$9 = [
293
+ "................",
294
+ ...IDLE$9.slice(1, 5),
295
+ "...dxaaaaaxad...",
296
+ ...IDLE$9.slice(6, 11),
297
+ "....d..dd..d....",
298
+ "....f......f...."
299
+ ];
300
+ const WORKING_0$9 = [
301
+ ...IDLE$9.slice(0, 6),
302
+ "...dabwwwbad....",
303
+ ...IDLE$9.slice(7)
304
+ ];
305
+ const WORKING_1$9 = [
306
+ ...IDLE$9.slice(0, 6),
307
+ "...dabwwwbad....",
308
+ ".g.daawwwwaad.g.",
309
+ ...IDLE$9.slice(8)
310
+ ];
311
+ const SUCCESS_0$9 = [
312
+ "....wwww........",
313
+ ...IDLE$9.slice(1, 5),
314
+ "...d*aaaaa*ad...",
315
+ ...IDLE$9.slice(6, 7),
316
+ ".gdaawwwwaadg...",
317
+ ...IDLE$9.slice(8)
318
+ ];
319
+ const SUCCESS_1$9 = [
320
+ "..wwww..........",
321
+ ...IDLE$9.slice(1, 5),
322
+ "...d*aaaaa*ad...",
323
+ ...IDLE$9.slice(6, 7),
324
+ ".gdaawwwwaadg...",
325
+ ...IDLE$9.slice(8)
326
+ ];
327
+ const FAILED$9 = [
328
+ "........?.......",
329
+ ...IDLE$9.slice(1, 5),
330
+ "...dxaaaaaxad...",
331
+ ...IDLE$9.slice(6, 12),
332
+ ".....fww.f......"
333
+ ];
334
+ const bird = {
335
+ id: "bird",
336
+ name: "小鸟",
337
+ palette: {
338
+ d: "#2D5A8A",
339
+ a: "#5AB0FF",
340
+ g: "#3E8FE0",
341
+ w: "#EAF6FF",
342
+ b: "#F5A623",
343
+ f: "#F5A623",
344
+ E: "#1F2937",
345
+ e: "#2D5A8A",
346
+ "*": "#FFD93D",
347
+ x: "#1F2937",
348
+ "?": "#FFD93D"
349
+ },
350
+ frames: {
351
+ idle: [IDLE$9],
352
+ walk: [WALK_0$9, WALK_1$9],
353
+ sleep: [SLEEP$9],
354
+ excited: [EXCITED_0$9, EXCITED_1$9],
355
+ drag: [DRAG$9],
356
+ working: [WORKING_0$9, WORKING_1$9],
357
+ success: [SUCCESS_0$9, SUCCESS_1$9],
358
+ failed: [FAILED$9]
359
+ }
360
+ };
361
+ const IDLE$8 = [
362
+ "...oo......oo...",
363
+ "..oiao....oaio..",
364
+ "..oaaooooooaao..",
365
+ ".oaarraarraaaao.",
366
+ ".oaaaaaaaaaaaao.",
367
+ ".oaaEaaaaaaEaao.",
368
+ ".oaabaccccabaao.",
369
+ ".oaaacnmmncaaao.",
370
+ "..oaaaccccaaao..",
371
+ "..oaaaaaaaaaooo.",
372
+ ".ooaaaaaaaaooao.",
373
+ "..oopp....ppoao.",
374
+ "..oooo....oooo.."
375
+ ];
376
+ const WALK_0$8 = [
377
+ ...IDLE$8.slice(0, 9),
378
+ "..oaaaaaaaaaaoo.",
379
+ "..oaaaaaaaaooao.",
380
+ "..oopp.....poao.",
381
+ "..oooo.....ooo.."
382
+ ];
383
+ const WALK_1$8 = [
384
+ ...IDLE$8.slice(0, 9),
385
+ "..oaaaaaaaaao...",
386
+ ".ooaaaaaaaaaooo.",
387
+ "..op.....ppoao..",
388
+ "...oo....oooo..."
389
+ ];
390
+ const SLEEP$8 = [
391
+ "................",
392
+ "................",
393
+ "...oo......oo...",
394
+ "..oiao....oaio..",
395
+ "..oaaooooooaao..",
396
+ ".oaaeaaaaaaeaao.",
397
+ ".oaabccccccbaao.",
398
+ "..oaaacnncaaao..",
399
+ ".ooaaaaaaaaaaoo.",
400
+ ".oaccccccccccao.",
401
+ ".oaaaaaaaaaaoo..",
402
+ "..oooooooooo....",
403
+ "................"
404
+ ];
405
+ const EXCITED_0$8 = [
406
+ ...IDLE$8.slice(0, 5),
407
+ ".oaa*aaaaaa*aao.",
408
+ ".oaabaccccabaao.",
409
+ ".oaaacnwwncaaao.",
410
+ "p.oaaaccccaaao.p",
411
+ "..oaaaaaaaaaooo.",
412
+ ".ooaaaaaaaaooao.",
413
+ "..oopp....ppoao.",
414
+ "..oooo....oooo.."
415
+ ];
416
+ const EXCITED_1$8 = [
417
+ ...IDLE$8.slice(0, 5),
418
+ ".oaa*aaaaaa*aao.",
419
+ ".oaabaccccabaao.",
420
+ ".oaaacnwwncaaao.",
421
+ ".poaaaccccaaaop.",
422
+ "..oaaaaaaaaao...",
423
+ ".ooaaaaaaaaaaoo.",
424
+ "...opp..ppoao...",
425
+ "...ooo..oooo...."
426
+ ];
427
+ const DRAG$8 = [
428
+ "................",
429
+ ".oo..........oo.",
430
+ "..oaa......aao..",
431
+ "..oaaooooooaao..",
432
+ ".oaarraarraaaao.",
433
+ ".oaaxaaaaaaxaao.",
434
+ ".oaabaccccabaao.",
435
+ ".oaaacnwwncaaao.",
436
+ "p.oaaaaaaaaaao.p",
437
+ "..oaaaaaaaaaooo.",
438
+ ".ooaaaaaaaaooao.",
439
+ "..op......poao..",
440
+ ".ooo......oooo.."
441
+ ];
442
+ const WORKING_0$8 = [
443
+ ...IDLE$8.slice(0, 11),
444
+ "..oapp....ppaao.",
445
+ ".owwwwwwwwwwwwo."
446
+ ];
447
+ const WORKING_1$8 = [
448
+ ...IDLE$8.slice(0, 5),
449
+ ".oaaeaaaaaaEaao.",
450
+ ...IDLE$8.slice(6, 11),
451
+ "..oapp....ppaao.",
452
+ ".owwwwwwwwwwwwo."
453
+ ];
454
+ const SUCCESS_0$8 = [
455
+ "*..oo......oo..*",
456
+ ...IDLE$8.slice(1, 5),
457
+ ".oaa*aaaaaa*aao.",
458
+ ...IDLE$8.slice(6, 7),
459
+ ".oaaacnwwncaaao.",
460
+ "p.oaaaccccaaao.p",
461
+ ...IDLE$8.slice(9)
462
+ ];
463
+ const SUCCESS_1$8 = [
464
+ "*..oo......oo..*",
465
+ ...IDLE$8.slice(1, 5),
466
+ ".oaa*aaaaaa*aao.",
467
+ ...IDLE$8.slice(6, 7),
468
+ "p.oaaacnwwncaaop",
469
+ ...IDLE$8.slice(8)
470
+ ];
471
+ const FAILED$8 = [
472
+ "....?...........",
473
+ ...IDLE$8.slice(0, 5),
474
+ ".oaaxaaaaaaxaao.",
475
+ ...IDLE$8.slice(6, 7),
476
+ ".oaaacnwwncaaao.",
477
+ ...IDLE$8.slice(8, 10),
478
+ ...IDLE$8.slice(11)
479
+ ];
480
+ const cat = {
481
+ id: "cat",
482
+ name: "橘猫",
483
+ palette: {
484
+ o: "#6E351B",
485
+ a: "#F39A24",
486
+ i: "#FFB4AE",
487
+ r: "#B9531F",
488
+ c: "#FFE4B0",
489
+ b: "#F57968",
490
+ E: "#2A211D",
491
+ e: "#6E351B",
492
+ n: "#D94F45",
493
+ m: "#6E351B",
494
+ w: "#FFF7E7",
495
+ "*": "#FFE35A",
496
+ p: "#6E351B",
497
+ x: "#2A211D",
498
+ "?": "#FFE35A"
499
+ },
500
+ frames: {
501
+ idle: [IDLE$8],
502
+ walk: [WALK_0$8, WALK_1$8],
503
+ sleep: [SLEEP$8],
504
+ excited: [EXCITED_0$8, EXCITED_1$8],
505
+ drag: [DRAG$8],
506
+ working: [WORKING_0$8, WORKING_1$8],
507
+ success: [SUCCESS_0$8, SUCCESS_1$8],
508
+ failed: [FAILED$8]
509
+ }
510
+ };
511
+ const IDLE$7 = [
512
+ ".......s........",
513
+ "......sss.......",
514
+ ".....dddddd.....",
515
+ "....daaaaaad....",
516
+ "...daaaaaaaad...",
517
+ ".daaaaaaaaaaad..",
518
+ ".daaEaaaaaaEaad.",
519
+ ".daaaaaaaaaaad..",
520
+ ".daaaaammaaaaad.",
521
+ ".daaaaaaaaaaad..",
522
+ "...daaaaaaaad...",
523
+ "....daaaaaad....",
524
+ "....dd....dd...."
525
+ ];
526
+ const WALK_0$7 = [...IDLE$7];
527
+ const WALK_1$7 = [...IDLE$7.slice(0, 12), ".....dd..dd....."];
528
+ const SLEEP$7 = [...IDLE$7.slice(0, 6), ".daaeaaaaaaeaad.", ...IDLE$7.slice(7)];
529
+ const EXCITED_0$7 = [
530
+ ...IDLE$7.slice(0, 6),
531
+ ".daa*aaaaaa*aad.",
532
+ ".daaaaaaaaaaad..",
533
+ ".daaaammmmaaaad.",
534
+ ...IDLE$7.slice(9)
535
+ ];
536
+ const EXCITED_1$7 = [
537
+ ...IDLE$7.slice(0, 6),
538
+ ".daa*aaaaaa*aad.",
539
+ ".paaaaaaaaaaap..",
540
+ ".daaaammmmaaaad.",
541
+ ...IDLE$7.slice(9, 12),
542
+ ".....dd..dd....."
543
+ ];
544
+ const DRAG$7 = [
545
+ "................",
546
+ ...IDLE$7.slice(1, 6),
547
+ ".daaxaaaaaaxaad.",
548
+ ".daaaaaaaaaaad..",
549
+ ".daaaammmmaaaad.",
550
+ ...IDLE$7.slice(9, 12),
551
+ "...d..d..d..d..."
552
+ ];
553
+ const WORKING_0$7 = [
554
+ ...IDLE$7.slice(0, 8),
555
+ ".daaawwwwwaaad..",
556
+ ".daawwwwwwwaad..",
557
+ ...IDLE$7.slice(10)
558
+ ];
559
+ const WORKING_1$7 = [
560
+ ...IDLE$7.slice(0, 7),
561
+ ".daaawwwwwaaad..",
562
+ ".daawwwwwwwaad..",
563
+ ...IDLE$7.slice(9)
564
+ ];
565
+ const SUCCESS_0$7 = [
566
+ "......s.s.......",
567
+ ".....sssss......",
568
+ ...IDLE$7.slice(2, 6),
569
+ ".daa*aaaaaa*aad.",
570
+ ".paaaaaaaaaaap..",
571
+ ".daaaammmmaaaad.",
572
+ ...IDLE$7.slice(9)
573
+ ];
574
+ const SUCCESS_1$7 = [
575
+ ".......s........",
576
+ ".....ss.ss......",
577
+ ...IDLE$7.slice(2, 6),
578
+ ".daa*aaaaaa*aad.",
579
+ ".paaaaaaaaaaap..",
580
+ ".daaaammmmaaaad.",
581
+ ...IDLE$7.slice(9)
582
+ ];
583
+ const FAILED$7 = [
584
+ "................",
585
+ "........ss......",
586
+ ...IDLE$7.slice(2, 6),
587
+ ".daaxaaaaaaxaad.",
588
+ ...IDLE$7.slice(7, 8),
589
+ ".daamamamamaad..",
590
+ ...IDLE$7.slice(9)
591
+ ];
592
+ const claude = {
593
+ id: "claude",
594
+ name: "Claude 小宠",
595
+ palette: {
596
+ s: "#4ADE80",
597
+ d: "#C2612A",
598
+ a: "#E8833A",
599
+ E: "#2D2D2D",
600
+ e: "#C2612A",
601
+ m: "#8A4A1F",
602
+ "*": "#FFD93D",
603
+ p: "#C2612A",
604
+ x: "#2D2D2D",
605
+ w: "#FFF7E7"
606
+ },
607
+ frames: {
608
+ idle: [IDLE$7],
609
+ walk: [WALK_0$7, WALK_1$7],
610
+ sleep: [SLEEP$7],
611
+ excited: [EXCITED_0$7, EXCITED_1$7],
612
+ drag: [DRAG$7],
613
+ working: [WORKING_0$7, WORKING_1$7],
614
+ success: [SUCCESS_0$7, SUCCESS_1$7],
615
+ failed: [FAILED$7]
616
+ }
617
+ };
618
+ const IDLE$6 = [
619
+ ".......t........",
620
+ "................",
621
+ ".....dddddd.....",
622
+ "....daaaaaad....",
623
+ "...daaaaaaaad...",
624
+ "..daaaaaaaaad...",
625
+ "..daaEaaaaEaad..",
626
+ "..daaaaaaaaad...",
627
+ "..daaaammaaaad..",
628
+ "..daaaaaaaaad...",
629
+ "...daaaaaaaad...",
630
+ "....daaaaaad....",
631
+ "....dd....dd...."
632
+ ];
633
+ const WALK_0$6 = [...IDLE$6];
634
+ const WALK_1$6 = [...IDLE$6.slice(0, 12), ".....dd..dd....."];
635
+ const SLEEP$6 = [...IDLE$6.slice(0, 6), "..daaeaaaaeaad..", ...IDLE$6.slice(7)];
636
+ const EXCITED_0$6 = [
637
+ ...IDLE$6.slice(0, 6),
638
+ "..daa*aaaa*aad..",
639
+ "..daaaaaaaaad...",
640
+ "..daaaammmmaad..",
641
+ ...IDLE$6.slice(9)
642
+ ];
643
+ const EXCITED_1$6 = [
644
+ ...IDLE$6.slice(0, 6),
645
+ "..daa*aaaa*aad..",
646
+ "..paaaaaaaaaap..",
647
+ "..daaaammmmaad..",
648
+ ...IDLE$6.slice(9, 12),
649
+ ".....dd..dd....."
650
+ ];
651
+ const DRAG$6 = [
652
+ "................",
653
+ ...IDLE$6.slice(1, 6),
654
+ "..daaxaaaaxaad..",
655
+ "..daaaaaaaaad...",
656
+ "..daaaammmmaad..",
657
+ ...IDLE$6.slice(9, 12),
658
+ "...d..d..d..d..."
659
+ ];
660
+ const WORKING_0$6 = [
661
+ ...IDLE$6.slice(0, 7),
662
+ "..dammmaaamad...",
663
+ ...IDLE$6.slice(8, 9),
664
+ "..daammmmaaad...",
665
+ ...IDLE$6.slice(10)
666
+ ];
667
+ const WORKING_1$6 = [
668
+ ...IDLE$6.slice(0, 7),
669
+ "..daaaammmaad...",
670
+ ...IDLE$6.slice(8, 9),
671
+ "..dammmmaaaad...",
672
+ ...IDLE$6.slice(10)
673
+ ];
674
+ const SUCCESS_0$6 = [
675
+ ".......*........",
676
+ ...IDLE$6.slice(1, 6),
677
+ "..daa*aaaa*aad..",
678
+ "..paaaaaaaaaap..",
679
+ "..daaaammmmaad..",
680
+ ...IDLE$6.slice(9)
681
+ ];
682
+ const SUCCESS_1$6 = [
683
+ ...IDLE$6.slice(0, 1),
684
+ ".......*........",
685
+ ...IDLE$6.slice(2, 6),
686
+ "..daa*aaaa*aad..",
687
+ "..paaaaaaaaaap..",
688
+ "..daaaammmmaad..",
689
+ ...IDLE$6.slice(9)
690
+ ];
691
+ const FAILED$6 = [
692
+ "................",
693
+ "......t.........",
694
+ ...IDLE$6.slice(2, 6),
695
+ "..daaxaaaaxaad..",
696
+ ...IDLE$6.slice(7, 8),
697
+ "..damamammamad..",
698
+ ...IDLE$6.slice(9)
699
+ ];
700
+ const codex = {
701
+ id: "codex",
702
+ name: "Codex 小宠",
703
+ palette: {
704
+ t: "#FFD93D",
705
+ d: "#2E9E5B",
706
+ a: "#4ADE80",
707
+ E: "#1A1A2E",
708
+ e: "#2E9E5B",
709
+ m: "#1A7A46",
710
+ "*": "#E8FFF3",
711
+ p: "#2E9E5B",
712
+ x: "#1A1A2E"
713
+ },
714
+ frames: {
715
+ idle: [IDLE$6],
716
+ walk: [WALK_0$6, WALK_1$6],
717
+ sleep: [SLEEP$6],
718
+ excited: [EXCITED_0$6, EXCITED_1$6],
719
+ drag: [DRAG$6],
720
+ working: [WORKING_0$6, WORKING_1$6],
721
+ success: [SUCCESS_0$6, SUCCESS_1$6],
722
+ failed: [FAILED$6]
723
+ }
724
+ };
725
+ const IDLE$5 = [
726
+ "................",
727
+ ".qqo........oqq.",
728
+ "qoaqo......oqaoq",
729
+ "qoaaaooooooaaaoq",
730
+ ".oaaaaaaaaaaaao.",
731
+ ".oaaEaaaaaaEaao.",
732
+ ".oaabaccccabaao.",
733
+ ".oaaacnnnncaaao.",
734
+ "..oaacmuucaao...",
735
+ "..oaaaccccaaao..",
736
+ "..oaaaaaaaaaaoo.",
737
+ "..oopp....ppoa.o",
738
+ "..oooo....ooooo."
739
+ ];
740
+ const WALK_0$5 = [
741
+ ...IDLE$5.slice(0, 10),
742
+ "..oaaaaaaaaaooo.",
743
+ "..oopp.....poa..",
744
+ "..oooo.....ooo.."
745
+ ];
746
+ const WALK_1$5 = [
747
+ ...IDLE$5.slice(0, 10),
748
+ "..oaaaaaaaaao..o",
749
+ "..op.....ppoa...",
750
+ "...oo....oooo..."
751
+ ];
752
+ const SLEEP$5 = [
753
+ "................",
754
+ "................",
755
+ ".qqo........oqq.",
756
+ "qoaqo......oqaoq",
757
+ "qoaaaooooooaaaoq",
758
+ ".oaaeaaaaaaeaao.",
759
+ ".oaabccccccbaao.",
760
+ ".oaaacnnnncaaao.",
761
+ "..oaaaccccaaao..",
762
+ ".ooaaaaaaaaaaoo.",
763
+ ".oaccccccccccao.",
764
+ "..oooooooooo....",
765
+ "................"
766
+ ];
767
+ const EXCITED_0$5 = [
768
+ ...IDLE$5.slice(0, 5),
769
+ ".oaa*aaaaaa*aao.",
770
+ ".oaabaccccabaao.",
771
+ ".oaaacnnnncaaao.",
772
+ "..oaacmuuucaao..",
773
+ "p.oaaaccccaaao.p",
774
+ "..oaaaaaaaaaaoo.",
775
+ "..oopp....ppoa.o",
776
+ "..oooo....ooooo."
777
+ ];
778
+ const EXCITED_1$5 = [
779
+ ...IDLE$5.slice(0, 5),
780
+ ".oaa*aaaaaa*aao.",
781
+ ".oaabaccccabaao.",
782
+ ".oaaacnnnncaaao.",
783
+ "..oaacmuuuucaao.",
784
+ ".poaaaccccaaaop.",
785
+ "..oaaaaaaaaao..o",
786
+ "...opp..ppoa....",
787
+ "...ooo..oooo...."
788
+ ];
789
+ const DRAG$5 = [
790
+ "................",
791
+ "qqo..........oqq",
792
+ ".qao........oaq.",
793
+ ".qoaaaooooooaoq.",
794
+ ".oaaaaaaaaaaaao.",
795
+ ".oaaxaaaaaaxaao.",
796
+ ".oaabaccccabaao.",
797
+ ".oaaacnnnncaaao.",
798
+ "..oaacmuuucaao..",
799
+ "p.oaaaaaaaaaao.p",
800
+ "..oaaaaaaaaaaoo.",
801
+ "..op......poa..o",
802
+ ".ooo......ooooo."
803
+ ];
804
+ const WORKING_0$5 = [
805
+ ...IDLE$5.slice(0, 8),
806
+ "..oacwwwwcaao...",
807
+ ...IDLE$5.slice(9)
808
+ ];
809
+ const WORKING_1$5 = [
810
+ ...IDLE$5.slice(0, 8),
811
+ "..oaacwwwwcaao..",
812
+ ...IDLE$5.slice(9, 12),
813
+ ".ooooo....oooo.."
814
+ ];
815
+ const SUCCESS_0$5 = [
816
+ "*..............*",
817
+ ...IDLE$5.slice(1, 5),
818
+ ".oaa*aaaaaa*aao.",
819
+ ...IDLE$5.slice(6, 8),
820
+ "p.oaacmuuucaao.p",
821
+ ...IDLE$5.slice(9)
822
+ ];
823
+ const SUCCESS_1$5 = [
824
+ "*..............*",
825
+ ...IDLE$5.slice(1, 5),
826
+ ".oaa*aaaaaa*aao.",
827
+ ...IDLE$5.slice(6, 7),
828
+ "p.oaaacnnnncaaop",
829
+ ...IDLE$5.slice(8)
830
+ ];
831
+ const FAILED$5 = [
832
+ "...........?....",
833
+ ...IDLE$5.slice(1, 5),
834
+ ".oaaxaaaaaaxaao.",
835
+ ...IDLE$5.slice(6, 8),
836
+ "..oaacmucaao....",
837
+ ...IDLE$5.slice(9, 12),
838
+ ".woooo....ooooo."
839
+ ];
840
+ const dog = {
841
+ id: "dog",
842
+ name: "小狗",
843
+ palette: {
844
+ o: "#553723",
845
+ a: "#D99A57",
846
+ q: "#8A552D",
847
+ c: "#FFE3B0",
848
+ b: "#EE7A6E",
849
+ E: "#211B17",
850
+ e: "#553723",
851
+ n: "#2D211A",
852
+ m: "#6F4028",
853
+ u: "#FF7485",
854
+ "*": "#FFE35A",
855
+ p: "#553723",
856
+ x: "#211B17",
857
+ w: "#FFF7E7",
858
+ "?": "#FFE35A"
859
+ },
860
+ frames: {
861
+ idle: [IDLE$5],
862
+ walk: [WALK_0$5, WALK_1$5],
863
+ sleep: [SLEEP$5],
864
+ excited: [EXCITED_0$5, EXCITED_1$5],
865
+ drag: [DRAG$5],
866
+ working: [WORKING_0$5, WORKING_1$5],
867
+ success: [SUCCESS_0$5, SUCCESS_1$5],
868
+ failed: [FAILED$5]
869
+ }
870
+ };
871
+ const hootUrl = "" + new URL("hoot-C7XVSf5y.webp", import.meta.url).href;
872
+ const hoot = {
873
+ id: "hoot",
874
+ name: "Professor Hoot",
875
+ image: hootUrl,
876
+ frameWidth: 192,
877
+ frameHeight: 208,
878
+ states: {
879
+ idle: { row: 0, frames: 6, frameMs: 917 },
880
+ walk: { row: 1, frames: 8, frameMs: 133 },
881
+ sleep: { row: 6, frames: 6, frameMs: 168 },
882
+ excited: { row: 4, frames: 5, frameMs: 168 },
883
+ drag: { row: 7, frames: 6, frameMs: 120 },
884
+ working: { row: 8, frames: 6, frameMs: 168 },
885
+ success: { row: 3, frames: 4, frameMs: 150 },
886
+ failed: { row: 5, frames: 8, frameMs: 153 }
887
+ }
888
+ };
889
+ const IDLE$4 = [
890
+ "....dddddddd....",
891
+ "..dddddddddddd..",
892
+ ".ddffffffffffdd.",
893
+ ".ddffffffffffdd.",
894
+ ".ddfEffffffEfdd.",
895
+ ".ddffffffffffdd.",
896
+ ".ddffwwwwwwffdd.",
897
+ ".ddffwnnnnwffdd.",
898
+ ".ddffwwmmwwffdd.",
899
+ "..ddffffffffdd..",
900
+ "...dddddddddd...",
901
+ "....dd....dd....",
902
+ "....dd....dd...."
903
+ ];
904
+ const WALK_0$4 = [...IDLE$4];
905
+ const WALK_1$4 = [...IDLE$4.slice(0, 12), ".....dd..dd....."];
906
+ const SLEEP$4 = [...IDLE$4.slice(0, 4), ".ddfeffffffefdd.", ...IDLE$4.slice(5)];
907
+ const EXCITED_0$4 = [
908
+ ...IDLE$4.slice(0, 4),
909
+ ".ddf*ffffff*fdd.",
910
+ ...IDLE$4.slice(5)
911
+ ];
912
+ const EXCITED_1$4 = [
913
+ ...IDLE$4.slice(0, 4),
914
+ ".ddf*ffffff*fdd.",
915
+ ...IDLE$4.slice(5, 9),
916
+ "..pffffffffffp..",
917
+ ...IDLE$4.slice(10, 12),
918
+ ".....dd..dd....."
919
+ ];
920
+ const DRAG$4 = [
921
+ "................",
922
+ ...IDLE$4.slice(1, 4),
923
+ ".ddfxffffffxfdd.",
924
+ ...IDLE$4.slice(5, 9),
925
+ "..pffffffffffp..",
926
+ ...IDLE$4.slice(10, 12),
927
+ "...d..d..d..d..."
928
+ ];
929
+ const WORKING_0$4 = [
930
+ ...IDLE$4.slice(0, 10),
931
+ "..pddwwwwwddp...",
932
+ ...IDLE$4.slice(11)
933
+ ];
934
+ const WORKING_1$4 = [
935
+ ...IDLE$4.slice(0, 10),
936
+ "..pddwpwwwddp...",
937
+ ...IDLE$4.slice(11)
938
+ ];
939
+ const SUCCESS_0$4 = [
940
+ "..*.dddddddd.*..",
941
+ ...IDLE$4.slice(1, 4),
942
+ ".ddf*ffffff*fdd.",
943
+ ...IDLE$4.slice(5, 9),
944
+ "..pffffffffffp..",
945
+ ...IDLE$4.slice(10)
946
+ ];
947
+ const SUCCESS_1$4 = [
948
+ "....dddddddd....",
949
+ "*..dddddddddd..*",
950
+ ...IDLE$4.slice(2, 4),
951
+ ".ddf*ffffff*fdd.",
952
+ ...IDLE$4.slice(5, 9),
953
+ "..pffffffffffp..",
954
+ ...IDLE$4.slice(10)
955
+ ];
956
+ const FAILED$4 = [
957
+ "....?...........",
958
+ ...IDLE$4.slice(1, 4),
959
+ ".ddfxffffffxfdd.",
960
+ ...IDLE$4.slice(5, 8),
961
+ ".ddfwwmmmmwwfdd.",
962
+ ...IDLE$4.slice(9)
963
+ ];
964
+ const lion = {
965
+ id: "lion",
966
+ name: "狮子",
967
+ palette: {
968
+ d: "#B3621F",
969
+ f: "#F5C542",
970
+ w: "#FFF3D6",
971
+ n: "#8A4A1F",
972
+ m: "#8A4A1F",
973
+ E: "#2D2D2D",
974
+ e: "#B3621F",
975
+ "*": "#FFD93D",
976
+ p: "#B3621F",
977
+ x: "#2D2D2D",
978
+ "?": "#FFD93D"
979
+ },
980
+ frames: {
981
+ idle: [IDLE$4],
982
+ walk: [WALK_0$4, WALK_1$4],
983
+ sleep: [SLEEP$4],
984
+ excited: [EXCITED_0$4, EXCITED_1$4],
985
+ drag: [DRAG$4],
986
+ working: [WORKING_0$4, WORKING_1$4],
987
+ success: [SUCCESS_0$4, SUCCESS_1$4],
988
+ failed: [FAILED$4]
989
+ }
990
+ };
991
+ const IDLE$3 = [
992
+ "................",
993
+ "................",
994
+ "..dddddddddddd..",
995
+ "..daaaaaaaaad...",
996
+ "..dabaaaaaabad..",
997
+ "..daEEaaaaEEad..",
998
+ "..daEEaaaaEEad..",
999
+ "..daaaammaaaad..",
1000
+ "..daaaammmmaad..",
1001
+ "..daammaammaad..",
1002
+ "..daaaaaaaaad...",
1003
+ "..dddddddddddd..",
1004
+ "...dd..dd..dd..."
1005
+ ];
1006
+ const WALK_0$3 = [...IDLE$3];
1007
+ const WALK_1$3 = [...IDLE$3.slice(0, 12), "..dd..dddd..dd.."];
1008
+ const SLEEP$3 = [
1009
+ ...IDLE$3.slice(0, 5),
1010
+ "..daeeaaaaeead..",
1011
+ "..daeeaaaaeead..",
1012
+ ...IDLE$3.slice(7)
1013
+ ];
1014
+ const EXCITED_0$3 = [
1015
+ ...IDLE$3.slice(0, 5),
1016
+ "..da**aaaa**ad..",
1017
+ "..da**aaaa**ad..",
1018
+ ...IDLE$3.slice(7)
1019
+ ];
1020
+ const EXCITED_1$3 = [
1021
+ ...IDLE$3.slice(0, 3),
1022
+ "..dllllllllld...",
1023
+ "..dllllllllld...",
1024
+ "..da**aaaa**ad..",
1025
+ "..da**aaaa**ad..",
1026
+ ...IDLE$3.slice(7, 10),
1027
+ "..dllllllllld...",
1028
+ ...IDLE$3.slice(11)
1029
+ ];
1030
+ const DRAG$3 = [
1031
+ ...IDLE$3.slice(0, 5),
1032
+ "..daxxaaaaxxad..",
1033
+ "..daxxaaaaxxad..",
1034
+ ...IDLE$3.slice(7, 12),
1035
+ "...d..d..d..d..."
1036
+ ];
1037
+ const WORKING_0$3 = [
1038
+ ...IDLE$3.slice(0, 12),
1039
+ "...dd..ddbbdd..."
1040
+ ];
1041
+ const WORKING_1$3 = [
1042
+ ...IDLE$3.slice(0, 12),
1043
+ "...ddlbdd..dd..."
1044
+ ];
1045
+ const SUCCESS_0$3 = [
1046
+ ...IDLE$3.slice(0, 5),
1047
+ "..da**aaaa**ad..",
1048
+ "..da**aaaa**ad..",
1049
+ ...IDLE$3.slice(7, 10),
1050
+ "..dllllllllld...",
1051
+ ...IDLE$3.slice(11)
1052
+ ];
1053
+ const SUCCESS_1$3 = [
1054
+ ...IDLE$3.slice(0, 2),
1055
+ "..dllllllllld...",
1056
+ ...IDLE$3.slice(3, 5),
1057
+ "..da**aaaa**ad..",
1058
+ "..da**aaaa**ad..",
1059
+ ...IDLE$3.slice(7, 10),
1060
+ "..dllllllllld...",
1061
+ ...IDLE$3.slice(11)
1062
+ ];
1063
+ const FAILED$3 = [
1064
+ ...IDLE$3.slice(0, 4),
1065
+ "..dabbaaaabbad..",
1066
+ "..daxxaaaaxxad..",
1067
+ "..daxxaaaaxxad..",
1068
+ ...IDLE$3.slice(7, 8),
1069
+ "..daammmmmmaad..",
1070
+ ...IDLE$3.slice(9)
1071
+ ];
1072
+ const minecraft = {
1073
+ id: "minecraft",
1074
+ name: "我的世界小宠",
1075
+ palette: {
1076
+ d: "#558B2F",
1077
+ a: "#7CB342",
1078
+ b: "#689F38",
1079
+ l: "#9CCC65",
1080
+ E: "#1A1A2E",
1081
+ e: "#558B2F",
1082
+ m: "#1A1A2E",
1083
+ "*": "#C5E1A5",
1084
+ x: "#33691E"
1085
+ },
1086
+ frames: {
1087
+ idle: [IDLE$3],
1088
+ walk: [WALK_0$3, WALK_1$3],
1089
+ sleep: [SLEEP$3],
1090
+ excited: [EXCITED_0$3, EXCITED_1$3],
1091
+ drag: [DRAG$3],
1092
+ working: [WORKING_0$3, WORKING_1$3],
1093
+ success: [SUCCESS_0$3, SUCCESS_1$3],
1094
+ failed: [FAILED$3]
1095
+ }
1096
+ };
1097
+ const IDLE$2 = [
1098
+ ".....dddddd.....",
1099
+ "....dddddddd....",
1100
+ "...dddddddddd...",
1101
+ "...ddwwwwwwdd...",
1102
+ "...dwEwwEwd.....",
1103
+ "...dwwbbwwd.....",
1104
+ "..ddwwwwwwwwdd..",
1105
+ ".kddwwwwwwwwddk.",
1106
+ ".kddwwwwwwwwddk.",
1107
+ "..ddwwwwwwwwdd..",
1108
+ "...dddddddddd...",
1109
+ "....ff....ff....",
1110
+ "...fff....fff..."
1111
+ ];
1112
+ const WALK_0$2 = [...IDLE$2];
1113
+ const WALK_1$2 = [...IDLE$2.slice(0, 11), ".....ff..ff.....", "....fff..fff...."];
1114
+ const SLEEP$2 = [...IDLE$2.slice(0, 4), "...dwewwewd.....", ...IDLE$2.slice(5)];
1115
+ const EXCITED_0$2 = [
1116
+ ...IDLE$2.slice(0, 4),
1117
+ "...dw*ww*wd.....",
1118
+ ...IDLE$2.slice(5)
1119
+ ];
1120
+ const EXCITED_1$2 = [
1121
+ ...IDLE$2.slice(0, 4),
1122
+ "...dw*ww*wd.....",
1123
+ ...IDLE$2.slice(5, 7),
1124
+ "kddwwwwwwwwddk..",
1125
+ ...IDLE$2.slice(8, 11),
1126
+ ".....ff..ff.....",
1127
+ "....fff..fff...."
1128
+ ];
1129
+ const DRAG$2 = [
1130
+ "................",
1131
+ ...IDLE$2.slice(1, 4),
1132
+ "...dwxwwxwd.....",
1133
+ ...IDLE$2.slice(5, 7),
1134
+ "kddwwwwwwwwddk..",
1135
+ "kddwwwwwwwwddk..",
1136
+ ...IDLE$2.slice(9, 11),
1137
+ "...ff......ff...",
1138
+ "..fff......fff.."
1139
+ ];
1140
+ const WORKING_0$2 = [
1141
+ ...IDLE$2.slice(0, 7),
1142
+ ".kddwffffffwddk.",
1143
+ ...IDLE$2.slice(8)
1144
+ ];
1145
+ const WORKING_1$2 = [
1146
+ ...IDLE$2.slice(0, 6),
1147
+ "..ddwffffffwdd..",
1148
+ ...IDLE$2.slice(7)
1149
+ ];
1150
+ const SUCCESS_0$2 = [
1151
+ ".....ffffff.....",
1152
+ ...IDLE$2.slice(1, 4),
1153
+ "...dw*ww*wd.....",
1154
+ ...IDLE$2.slice(5, 7),
1155
+ "kddwwwwwwwwddk..",
1156
+ ...IDLE$2.slice(8)
1157
+ ];
1158
+ const SUCCESS_1$2 = [
1159
+ "................",
1160
+ "....ffffff......",
1161
+ ...IDLE$2.slice(2, 4),
1162
+ "...dw*ww*wd.....",
1163
+ ...IDLE$2.slice(5, 7),
1164
+ "kddwwwwwwwwddk..",
1165
+ ...IDLE$2.slice(8)
1166
+ ];
1167
+ const FAILED$2 = [
1168
+ "..?.............",
1169
+ ...IDLE$2.slice(1, 4),
1170
+ "...dwxwwxwd.....",
1171
+ ...IDLE$2.slice(5, 12),
1172
+ "..fff.ffffff...."
1173
+ ];
1174
+ const penguin = {
1175
+ id: "penguin",
1176
+ name: "企鹅",
1177
+ palette: {
1178
+ d: "#1F2937",
1179
+ w: "#F9FAFB",
1180
+ k: "#374151",
1181
+ b: "#F59E0B",
1182
+ f: "#F59E0B",
1183
+ E: "#111827",
1184
+ e: "#374151",
1185
+ "*": "#FFD93D",
1186
+ x: "#111827",
1187
+ "?": "#FFD93D"
1188
+ },
1189
+ frames: {
1190
+ idle: [IDLE$2],
1191
+ walk: [WALK_0$2, WALK_1$2],
1192
+ sleep: [SLEEP$2],
1193
+ excited: [EXCITED_0$2, EXCITED_1$2],
1194
+ drag: [DRAG$2],
1195
+ working: [WORKING_0$2, WORKING_1$2],
1196
+ success: [SUCCESS_0$2, SUCCESS_1$2],
1197
+ failed: [FAILED$2]
1198
+ }
1199
+ };
1200
+ const IDLE$1 = [
1201
+ "...dd......dd...",
1202
+ "..daad....daad..",
1203
+ "..daaddddddaad..",
1204
+ ".daattttttttaad.",
1205
+ ".daaaaaaaaaaaad.",
1206
+ ".daaEaaaaaaEaad.",
1207
+ ".taaaaaaaaaaaat.",
1208
+ ".daaaanmmnaaaad.",
1209
+ ".taaaaaaaaaaaat.",
1210
+ "...daaaaaaaadd..",
1211
+ "...daaaaaaaaadt.",
1212
+ "....dd....dd....",
1213
+ "....dd....dd...."
1214
+ ];
1215
+ const WALK_0$1 = [...IDLE$1];
1216
+ const WALK_1$1 = [...IDLE$1.slice(0, 12), ".....dd..dd....."];
1217
+ const SLEEP$1 = [...IDLE$1.slice(0, 5), ".daaeaaaaaaeaad.", ...IDLE$1.slice(6)];
1218
+ const EXCITED_0$1 = [
1219
+ ...IDLE$1.slice(0, 5),
1220
+ ".daa*aaaaaa*aad.",
1221
+ ".taaaaaaaaaaaat.",
1222
+ ".daaaammmmaaaad.",
1223
+ ...IDLE$1.slice(8)
1224
+ ];
1225
+ const EXCITED_1$1 = [
1226
+ ...IDLE$1.slice(0, 5),
1227
+ ".daa*aaaaaa*aad.",
1228
+ ".paaaaaaaaaaaap.",
1229
+ ".daaaammmmaaaad.",
1230
+ ...IDLE$1.slice(8, 12),
1231
+ ".....dd..dd....."
1232
+ ];
1233
+ const DRAG$1 = [
1234
+ "................",
1235
+ ...IDLE$1.slice(1, 5),
1236
+ ".daaxaaaaaaxaad.",
1237
+ ".taaaaaaaaaaaat.",
1238
+ ".daaaammmmaaaad.",
1239
+ ...IDLE$1.slice(8, 12),
1240
+ "...d..d..d..d..."
1241
+ ];
1242
+ const WORKING_0$1 = [
1243
+ ...IDLE$1.slice(0, 11),
1244
+ "...dpp....ppd...",
1245
+ "...dwwwwwwwwd..."
1246
+ ];
1247
+ const WORKING_1$1 = [
1248
+ ...IDLE$1.slice(0, 11),
1249
+ "...dp.....pdp...",
1250
+ "...dwwwwwwwwd..."
1251
+ ];
1252
+ const SUCCESS_0$1 = [
1253
+ ...IDLE$1.slice(0, 5),
1254
+ ".daa*aaaaaa*aad.",
1255
+ ...IDLE$1.slice(6, 7),
1256
+ ".daaaammmmaaaad.",
1257
+ ".paaaaaaaaaaaap.",
1258
+ "...daaaaaaaaddt.",
1259
+ ...IDLE$1.slice(10)
1260
+ ];
1261
+ const SUCCESS_1$1 = [
1262
+ ...IDLE$1.slice(0, 5),
1263
+ ".daa*aaaaaa*aad.",
1264
+ "ptaaaaaaaaaaatp.",
1265
+ ".daaaammmmaaaad.",
1266
+ ...IDLE$1.slice(8, 9),
1267
+ "...daaaaaaaaddt.",
1268
+ ...IDLE$1.slice(10)
1269
+ ];
1270
+ const FAILED$1 = [
1271
+ "..........?.....",
1272
+ ...IDLE$1.slice(1, 5),
1273
+ ".daaxaaaaaaxaad.",
1274
+ ...IDLE$1.slice(6, 7),
1275
+ ".daaaammmmaaaad.",
1276
+ ...IDLE$1.slice(8)
1277
+ ];
1278
+ const tiger = {
1279
+ id: "tiger",
1280
+ name: "老虎",
1281
+ palette: {
1282
+ d: "#7A3E10",
1283
+ a: "#F58B1F",
1284
+ t: "#2D2D2D",
1285
+ n: "#E2543E",
1286
+ m: "#7A3E10",
1287
+ E: "#2D2D2D",
1288
+ e: "#7A3E10",
1289
+ "*": "#FFD93D",
1290
+ p: "#7A3E10",
1291
+ x: "#2D2D2D",
1292
+ w: "#FFF3D6",
1293
+ "?": "#FFD93D"
1294
+ },
1295
+ frames: {
1296
+ idle: [IDLE$1],
1297
+ walk: [WALK_0$1, WALK_1$1],
1298
+ sleep: [SLEEP$1],
1299
+ excited: [EXCITED_0$1, EXCITED_1$1],
1300
+ drag: [DRAG$1],
1301
+ working: [WORKING_0$1, WORKING_1$1],
1302
+ success: [SUCCESS_0$1, SUCCESS_1$1],
1303
+ failed: [FAILED$1]
1304
+ }
1305
+ };
1306
+ const IDLE = [
1307
+ "....w...w.......",
1308
+ ".....w.w........",
1309
+ "......w.........",
1310
+ "....dddddddd....",
1311
+ "..dddddddddddd..",
1312
+ ".daaaaaaaaaaad..",
1313
+ ".daEaaaaaaaaaad.",
1314
+ ".daaaaaaaaaaadf.",
1315
+ ".daawwwwwwaaadff",
1316
+ "..dawwwwwwaad.f.",
1317
+ "...ddwwwwddddd..",
1318
+ "......dddd......",
1319
+ ".......dd......."
1320
+ ];
1321
+ const WALK_0 = [...IDLE];
1322
+ const WALK_1 = [
1323
+ "................",
1324
+ "................",
1325
+ "................",
1326
+ ...IDLE.slice(3, 7),
1327
+ ".daaaaaaaaaaadf.",
1328
+ ".daawwwwwwaaadff",
1329
+ "..dawwwwwwaadf..",
1330
+ "...ddwwwwddddd..",
1331
+ "......dddd......",
1332
+ "................"
1333
+ ];
1334
+ const SLEEP = [
1335
+ "................",
1336
+ "................",
1337
+ "................",
1338
+ ...IDLE.slice(3, 6),
1339
+ ".daeaaaaaaaaaad.",
1340
+ ...IDLE.slice(7)
1341
+ ];
1342
+ const EXCITED_0 = [
1343
+ "...w.....w......",
1344
+ "....w...w.......",
1345
+ ".....w.w........",
1346
+ ...IDLE.slice(3, 6),
1347
+ ".da*aaaaaaaaaad.",
1348
+ ...IDLE.slice(7)
1349
+ ];
1350
+ const EXCITED_1 = [
1351
+ "..w.......w.....",
1352
+ "...w.....w......",
1353
+ "....w...w.......",
1354
+ ...IDLE.slice(3, 6),
1355
+ ".da*aaaaaaaaaad.",
1356
+ ...IDLE.slice(7)
1357
+ ];
1358
+ const DRAG = [
1359
+ "................",
1360
+ "....w...........",
1361
+ "................",
1362
+ ...IDLE.slice(3, 6),
1363
+ ".daxaaaaaaaaaad.",
1364
+ ...IDLE.slice(7, 11),
1365
+ ".....d....d.....",
1366
+ "................"
1367
+ ];
1368
+ const WORKING_0 = [
1369
+ ".....wwww.......",
1370
+ "......w.........",
1371
+ "......w.........",
1372
+ ...IDLE.slice(3)
1373
+ ];
1374
+ const WORKING_1 = [
1375
+ "....wwww........",
1376
+ "......w.........",
1377
+ "......w.........",
1378
+ ...IDLE.slice(3)
1379
+ ];
1380
+ const SUCCESS_0 = [
1381
+ ".w...........w..",
1382
+ "..w.........w...",
1383
+ "...w.......w....",
1384
+ ...IDLE.slice(3, 6),
1385
+ ".da*aaaaaaaaaad.",
1386
+ ...IDLE.slice(7)
1387
+ ];
1388
+ const SUCCESS_1 = [
1389
+ "...w.......w....",
1390
+ "..w.........w...",
1391
+ ".w...........w..",
1392
+ ...IDLE.slice(3, 6),
1393
+ ".da*aaaaaaaaaad.",
1394
+ ...IDLE.slice(7)
1395
+ ];
1396
+ const FAILED = [
1397
+ "................",
1398
+ "....w......w....",
1399
+ "................",
1400
+ ...IDLE.slice(3, 6),
1401
+ ".daxaaaaaaaaaad.",
1402
+ ...IDLE.slice(7)
1403
+ ];
1404
+ const whale = {
1405
+ id: "whale",
1406
+ name: "蓝鲸",
1407
+ palette: {
1408
+ d: "#1E4A6E",
1409
+ a: "#4A8FC7",
1410
+ w: "#BFE3F7",
1411
+ f: "#163A58",
1412
+ E: "#13293D",
1413
+ e: "#1E4A6E",
1414
+ "*": "#FFD93D",
1415
+ x: "#13293D"
1416
+ },
1417
+ frames: {
1418
+ idle: [IDLE],
1419
+ walk: [WALK_0, WALK_1],
1420
+ sleep: [SLEEP],
1421
+ excited: [EXCITED_0, EXCITED_1],
1422
+ drag: [DRAG],
1423
+ working: [WORKING_0, WORKING_1],
1424
+ success: [SUCCESS_0, SUCCESS_1],
1425
+ failed: [FAILED]
1426
+ }
1427
+ };
1428
+ const robotBlueUrl = "" + new URL("robot-blue-CFH9bWjZ.png", import.meta.url).href;
1429
+ const still = { row: 0, frames: 1, frameMs: 180 };
1430
+ const robotBlue = {
1431
+ id: "robot-blue",
1432
+ name: "蓝色协作机器人",
1433
+ image: robotBlueUrl,
1434
+ imageLayout: "single",
1435
+ frameWidth: 1024,
1436
+ frameHeight: 1536,
1437
+ displaySize: { width: 180, height: 270 },
1438
+ recommendedWindow: { width: 260, height: 320 },
1439
+ smoothing: true,
1440
+ states: {
1441
+ idle: { ...still, frameMs: 220 },
1442
+ walk: { ...still, frameMs: 110 },
1443
+ sleep: { ...still, frameMs: 260 },
1444
+ excited: { ...still, frameMs: 110 },
1445
+ drag: { ...still, frameMs: 120 },
1446
+ working: { ...still, frameMs: 150 },
1447
+ success: { ...still, frameMs: 110 },
1448
+ failed: { ...still, frameMs: 180 }
1449
+ },
1450
+ anchors: {
1451
+ ground: { x: 0.5, y: 0.955 },
1452
+ bubble: { x: 0.5, y: 0.08 },
1453
+ effects: {
1454
+ leftHand: { x: 0.2, y: 0.66 },
1455
+ rightHand: { x: 0.8, y: 0.66 },
1456
+ screen: { x: 0.5, y: 0.33 }
1457
+ },
1458
+ contentBounds: { x: 0.08, y: 0.02, width: 0.84, height: 0.94 }
1459
+ }
1460
+ };
1461
+ const skins = {
1462
+ codex,
1463
+ claude,
1464
+ minecraft,
1465
+ cat,
1466
+ dog,
1467
+ bird,
1468
+ lion,
1469
+ tiger,
1470
+ whale,
1471
+ penguin
1472
+ };
1473
+ const spriteSkins = { hoot, "robot-blue": robotBlue };
1474
+ const defaultSkin = codex;
1475
+ function resolveSkin(id) {
1476
+ const ascii = skins[id];
1477
+ if (ascii) return { kind: "ascii", skin: ascii };
1478
+ const sprite = spriteSkins[id];
1479
+ if (sprite) return { kind: "sprite", skin: sprite };
1480
+ return void 0;
1481
+ }
1482
+ class Bubble {
1483
+ el;
1484
+ hideTimer;
1485
+ constructor(container) {
1486
+ this.el = document.createElement("div");
1487
+ this.el.className = "bubble";
1488
+ container.appendChild(this.el);
1489
+ }
1490
+ show(text, ttl = 6e3) {
1491
+ clearTimeout(this.hideTimer);
1492
+ this.el.textContent = text;
1493
+ this.el.classList.remove("pop", "fade");
1494
+ void this.el.offsetWidth;
1495
+ this.el.classList.add("show", "pop");
1496
+ this.hideTimer = setTimeout(() => {
1497
+ this.el.classList.remove("show");
1498
+ this.el.classList.add("fade");
1499
+ }, ttl);
1500
+ }
1501
+ setAnchor(x, y) {
1502
+ this.el.style.left = `${Math.min(1, Math.max(0, x)) * 100}%`;
1503
+ this.el.style.top = `${Math.min(1, Math.max(0, y)) * 100}%`;
1504
+ }
1505
+ }
1506
+ class RewardFloat {
1507
+ el;
1508
+ hideTimer;
1509
+ constructor(container) {
1510
+ this.el = document.createElement("div");
1511
+ this.el.className = "reward-float";
1512
+ this.el.setAttribute("aria-live", "polite");
1513
+ container.appendChild(this.el);
1514
+ }
1515
+ show(amount, label = "小鱼干") {
1516
+ clearTimeout(this.hideTimer);
1517
+ this.el.textContent = `+${Math.round(amount)} ${label}`;
1518
+ this.el.classList.remove("play");
1519
+ void this.el.offsetWidth;
1520
+ this.el.classList.add("play");
1521
+ this.hideTimer = setTimeout(() => {
1522
+ this.el.classList.remove("play");
1523
+ }, 2200);
1524
+ }
1525
+ }
1526
+ const TICK_MS = 350;
1527
+ const SPRITE_DRAW_MS = 100;
1528
+ const canvas = document.getElementById("pet");
1529
+ const identityBadge = document.getElementById("pet-identity");
1530
+ const bubble = new Bubble(document.body);
1531
+ const reward = new RewardFloat(document.body);
1532
+ let entry = { kind: "ascii", skin: defaultSkin };
1533
+ let asciiSkin = defaultSkin;
1534
+ const renderer = new PixelRenderer(canvas);
1535
+ const spriteRenderer = new SpriteRenderer(canvas, () => draw());
1536
+ const animator = new Animator(() => asciiSkin);
1537
+ animator.onMove = (dx, dy) => window.petApi.move(dx, dy);
1538
+ let lastState = animator.state;
1539
+ let stateStart = performance.now();
1540
+ function spriteElapsed() {
1541
+ if (animator.state !== lastState) {
1542
+ lastState = animator.state;
1543
+ stateStart = performance.now();
1544
+ }
1545
+ return performance.now() - stateStart;
1546
+ }
1547
+ function draw() {
1548
+ if (entry.kind === "sprite") {
1549
+ spriteRenderer.draw(entry.skin, animator.state, spriteElapsed(), {
1550
+ flip: animator.flip,
1551
+ sleeping: animator.state === "sleep",
1552
+ tick: animator.tickCount,
1553
+ hearts: animator.reaction === "hearts"
1554
+ });
1555
+ return;
1556
+ }
1557
+ renderer.draw(asciiSkin, animator.frame, {
1558
+ blink: animator.blink,
1559
+ flip: animator.flip,
1560
+ sleeping: animator.state === "sleep",
1561
+ tick: animator.tickCount,
1562
+ hearts: animator.reaction === "hearts"
1563
+ });
1564
+ }
1565
+ function applySkin(id) {
1566
+ const next = resolveSkin(id);
1567
+ if (!next) return;
1568
+ entry = next;
1569
+ if (next.kind === "ascii") {
1570
+ asciiSkin = next.skin;
1571
+ canvas.width = PIXEL_CANVAS_WIDTH;
1572
+ canvas.height = PIXEL_CANVAS_HEIGHT;
1573
+ bubble.setAnchor(0.5, 0.03);
1574
+ } else {
1575
+ spriteRenderer.load(next.skin);
1576
+ const anchor = next.skin.anchors?.bubble;
1577
+ bubble.setAnchor(anchor?.x ?? 0.5, anchor?.y ?? 0.03);
1578
+ }
1579
+ lastState = animator.state;
1580
+ stateStart = performance.now();
1581
+ draw();
1582
+ }
1583
+ setInterval(() => {
1584
+ animator.advance();
1585
+ draw();
1586
+ }, TICK_MS);
1587
+ setInterval(() => {
1588
+ if (entry.kind === "sprite") draw();
1589
+ }, SPRITE_DRAW_MS);
1590
+ draw();
1591
+ const GREETINGS = ["你好呀!", "一起玩吧!", "嗨~", "见到你真开心!"];
1592
+ window.petApi.onEvent((ev) => {
1593
+ if (ev.type === "skin") {
1594
+ applySkin(ev.skin);
1595
+ } else if (ev.type === "identity") {
1596
+ identityBadge.textContent = ev.label;
1597
+ identityBadge.dataset.kind = ev.kind;
1598
+ identityBadge.hidden = false;
1599
+ } else if (ev.type === "state") {
1600
+ animator.forceState(ev.state, ev.ttl);
1601
+ } else if (ev.type === "bubble") {
1602
+ bubble.show(ev.text, ev.ttl);
1603
+ } else if (ev.type === "reward") {
1604
+ reward.show(ev.amount, ev.label ?? "小鱼干");
1605
+ animator.react("hearts", 8);
1606
+ animator.forceState("excited", 8);
1607
+ } else if (ev.type === "interact") {
1608
+ if (ev.kind === "greet") {
1609
+ animator.react("hearts");
1610
+ animator.forceState("excited", 6);
1611
+ bubble.show(GREETINGS[Math.floor(Math.random() * GREETINGS.length)], 4e3);
1612
+ } else if (ev.kind === "approach") {
1613
+ animator.forceState("walk", 5, ev.dir);
1614
+ }
1615
+ }
1616
+ draw();
1617
+ });
1618
+ let dragging = false;
1619
+ let lastX = 0;
1620
+ let lastY = 0;
1621
+ canvas.addEventListener("mousedown", (e) => {
1622
+ if (e.button !== 0) return;
1623
+ dragging = true;
1624
+ lastX = e.screenX;
1625
+ lastY = e.screenY;
1626
+ animator.setDragging(true);
1627
+ window.petApi.drag("start");
1628
+ draw();
1629
+ });
1630
+ window.addEventListener("mousemove", (e) => {
1631
+ if (!dragging) return;
1632
+ const dx = e.screenX - lastX;
1633
+ const dy = e.screenY - lastY;
1634
+ if (dx !== 0 || dy !== 0) window.petApi.drag("move", dx, dy);
1635
+ lastX = e.screenX;
1636
+ lastY = e.screenY;
1637
+ });
1638
+ window.addEventListener("mouseup", () => {
1639
+ if (!dragging) return;
1640
+ dragging = false;
1641
+ window.petApi.drag("end");
1642
+ animator.setDragging(false);
1643
+ draw();
1644
+ });
1645
+ window.addEventListener("contextmenu", (e) => {
1646
+ e.preventDefault();
1647
+ if (dragging) {
1648
+ dragging = false;
1649
+ window.petApi.drag("end");
1650
+ animator.setDragging(false);
1651
+ draw();
1652
+ }
1653
+ window.petApi.openMenu();
1654
+ });
1655
+ window.addEventListener("blur", () => {
1656
+ if (!dragging) return;
1657
+ dragging = false;
1658
+ window.petApi.drag("end");
1659
+ animator.setDragging(false);
1660
+ draw();
1661
+ });