@mingxy/opencode-mascot 0.4.38 → 0.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mingxy/opencode-mascot",
3
- "version": "0.4.38",
3
+ "version": "0.5.0",
4
4
  "description": "OpenCode TUI mascot plugin framework - customizable ASCII mascots for your terminal",
5
5
  "author": "mingxy",
6
6
  "license": "MIT",
@@ -53,6 +53,7 @@ export function createAnimatedRenderer(pack: MascotPack): {
53
53
  bounce: () => void;
54
54
  showVersion: (version: string) => void;
55
55
  scatterIn: () => void;
56
+ explode: () => void;
56
57
  } {
57
58
  const anim = { ...DEFAULT_ANIM, ...pack.animations };
58
59
  const fg = pack.colors?.defaultFg || undefined;
@@ -69,12 +70,15 @@ export function createAnimatedRenderer(pack: MascotPack): {
69
70
  const [flashColor, setFlashColor] = createSignal<string | null>(null);
70
71
  const [dragMsg, setDragMsg] = createSignal<string | null>(null);
71
72
  const [zzz, setZzz] = createSignal<string | null>(null);
73
+ const [bomb, setBomb] = createSignal<{ fuse: string; count: string } | null>(null);
72
74
  const [scatter, setScatter] = createSignal<{ dx: number; dy: number }[] | null>(null);
73
75
 
74
76
  let flashTimer: ReturnType<typeof setInterval> | null = null;
75
77
  let dragMsgTimer: ReturnType<typeof setInterval> | null = null;
76
78
  let zzzTimer: ReturnType<typeof setInterval> | null = null;
77
79
  let scatterTimer: ReturnType<typeof setInterval> | null = null;
80
+ let bombTimer: ReturnType<typeof setTimeout> | null = null;
81
+ let explodeTimer: ReturnType<typeof setTimeout> | null = null;
78
82
  let bounceTimers: ReturnType<typeof setTimeout>[] = [];
79
83
  let celebrateTimers: ReturnType<typeof setTimeout>[] = [];
80
84
  let versionTimer: ReturnType<typeof setTimeout> | null = null;
@@ -107,6 +111,11 @@ export function createAnimatedRenderer(pack: MascotPack): {
107
111
  if (scatterTimer) { clearInterval(scatterTimer); scatterTimer = null; }
108
112
  setScatter(null);
109
113
  };
114
+ const stopBomb = () => {
115
+ if (bombTimer) { clearTimeout(bombTimer); bombTimer = null; }
116
+ if (explodeTimer) { clearTimeout(explodeTimer); explodeTimer = null; }
117
+ setBomb(null);
118
+ };
110
119
 
111
120
  const stopAllAnimations = () => {
112
121
  stopFlash();
@@ -226,7 +235,11 @@ export function createAnimatedRenderer(pack: MascotPack): {
226
235
  const delay = anim.walkMinDelay + Math.floor(Math.random() * (anim.walkMaxDelay - anim.walkMinDelay));
227
236
  return setTimeout(() => {
228
237
  if (currentState() === "idle" && !frameOverride() && walkStep === -1 && walkEnabled()) {
229
- startWalk();
238
+ if (Math.random() < 0.1) {
239
+ explode();
240
+ } else {
241
+ startWalk();
242
+ }
230
243
  }
231
244
  if (currentState() !== "sleeping") {
232
245
  walkTimeout = scheduleNextWalk();
@@ -285,6 +298,7 @@ export function createAnimatedRenderer(pack: MascotPack): {
285
298
  stopVersion();
286
299
  stopScatter();
287
300
  stopFall();
301
+ stopBomb();
288
302
  if (zzzTimer) { clearInterval(zzzTimer); zzzTimer = null; }
289
303
  });
290
304
 
@@ -301,6 +315,7 @@ export function createAnimatedRenderer(pack: MascotPack): {
301
315
  dragMsg();
302
316
  zzz();
303
317
  scatter();
318
+ bomb();
304
319
 
305
320
  for (const [, [get]] of extraSignals) {
306
321
  get();
@@ -344,6 +359,13 @@ export function createAnimatedRenderer(pack: MascotPack): {
344
359
  {cel ? <box position="absolute" top={-1} left={0}><text fg={flashColor() ?? fg}>{cel.text}</text></box> : null}
345
360
  {dm ? <box position="absolute" top={-1} left={0}><text fg="#FF4081">{dm}</text></box> : null}
346
361
  {zzz() ? <box position="absolute" top={-1} left={0}><text fg={flashColor() ?? fg}>{zzz()}</text></box> : null}
362
+ {bomb() ? (
363
+ <box position="absolute" top={-2} left={3}>
364
+ <text fg="#FF4444">{bomb()!.fuse}↘</text>
365
+ <text fg="#FF6666">{" ◉"}</text>
366
+ {bomb()!.count ? <text fg="#FFAA00">{bomb()!.count}</text> : null}
367
+ </box>
368
+ ) : null}
347
369
  {lines.map((line: string, i: number) => (
348
370
  <text fg={flashColor() ?? fg} left={sc?.[i]?.dx ?? 0} top={sc?.[i]?.dy ?? 0}>{line}</text>
349
371
  ))}
@@ -508,5 +530,45 @@ export function createAnimatedRenderer(pack: MascotPack): {
508
530
  }, 80);
509
531
  };
510
532
 
511
- return { element, setState, toggleWalk, setDragging, celebrateUpdate, bounce, showVersion, scatterIn };
533
+ const explode = () => {
534
+ stopBomb();
535
+ stopScatter();
536
+ setFrameOverride("thinking");
537
+ setBomb({ fuse: "✦", count: "³·" });
538
+
539
+ let fuseAlt = false;
540
+ const fuseTimer = setInterval(() => {
541
+ fuseAlt = !fuseAlt;
542
+ setBomb({ fuse: fuseAlt ? "✦" : "◌", count: "³·" });
543
+ }, 400);
544
+
545
+ bombTimer = setTimeout(() => {
546
+ clearInterval(fuseTimer);
547
+ setBomb({ fuse: fuseAlt ? "✦" : "◌", count: "²·" });
548
+ bombTimer = setTimeout(() => {
549
+ clearInterval(fuseTimer);
550
+ setBomb({ fuse: fuseAlt ? "✦" : "◌", count: "¹·" });
551
+ bombTimer = setTimeout(() => {
552
+ clearInterval(fuseTimer);
553
+ setBomb(null);
554
+ setFrameOverride(null);
555
+ setFlashColor("#FFFFFF");
556
+ const lineCount = getFrameLines(pack, "default").length;
557
+ const offsets = Array.from({ length: lineCount }, () => ({
558
+ dx: Math.floor((Math.random() - 0.5) * 30),
559
+ dy: Math.floor((Math.random() - 0.5) * 15),
560
+ }));
561
+ setScatter(offsets);
562
+ setCelebrate({ text: "ᵇᵒᵒᵐ~", count: 0 });
563
+ explodeTimer = setTimeout(() => {
564
+ setFlashColor(null);
565
+ setCelebrate(null);
566
+ scatterIn();
567
+ }, 1200);
568
+ }, 700);
569
+ }, 700);
570
+ }, 700);
571
+ };
572
+
573
+ return { element, setState, toggleWalk, setDragging, celebrateUpdate, bounce, showVersion, scatterIn, explode };
512
574
  }