@kernel.chat/kbot 3.87.0 → 3.93.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.
@@ -70,8 +70,10 @@ function dither(ctx, x, y, w, h, color1, color2, scale, ox, oy) {
70
70
  }
71
71
  /** Draw a 1px outline silhouette for a rectangular region */
72
72
  function outlineRect(ctx, x, y, w, h, color, scale, ox, oy) {
73
- // Outline is 1px larger on all sides
74
- px(ctx, x - 1, y - 1, w + 2, h + 2, color, scale, ox, oy);
73
+ px(ctx, x - 1, y - 1, w + 2, 1, color, scale, ox, oy); // top
74
+ px(ctx, x - 1, y + h, w + 2, 1, color, scale, ox, oy); // bottom
75
+ px(ctx, x - 1, y, 1, h, color, scale, ox, oy); // left
76
+ px(ctx, x + w, y, 1, h, color, scale, ox, oy); // right
75
77
  }
76
78
  // ─── Sub-drawers ───────────────────────────────────────────────
77
79
  function drawAntenna(ctx, s, ox, oy, glowColor, frame, breathPhase = 0) {
@@ -105,18 +107,18 @@ function drawHead(ctx, s, ox, oy, eyeColor, mood, frame, headShiftX) {
105
107
  const hy = 5;
106
108
  // 1px outline silhouette (technique 4)
107
109
  outlineRect(ctx, hx, hy, 14, 11, PAL.outline, s, ox, oy);
108
- // Sub-pixel AA on rounded corners: deep shadow pixels for smoother curves (technique 2)
110
+ // Head base (shadow layer)
111
+ px(ctx, hx, hy, 14, 11, PAL.bodyDark, s, ox, oy);
112
+ // Cut corners for rounded look — clearRect actually erases pixels (transparent fillRect does nothing)
113
+ ctx.clearRect(ox + hx * s, oy + hy * s, s, s);
114
+ ctx.clearRect(ox + (hx + 13) * s, oy + hy * s, s, s);
115
+ ctx.clearRect(ox + hx * s, oy + (hy + 10) * s, s, s);
116
+ ctx.clearRect(ox + (hx + 13) * s, oy + (hy + 10) * s, s, s);
117
+ // Sub-pixel AA on rounded corners — drawn AFTER clearing so they aren't overwritten (technique 2)
109
118
  px(ctx, hx - 1, hy, 1, 1, PAL.bodyDeepShadow, s, ox, oy);
110
119
  px(ctx, hx + 14, hy, 1, 1, PAL.bodyDeepShadow, s, ox, oy);
111
120
  px(ctx, hx - 1, hy + 10, 1, 1, PAL.bodyDeepShadow, s, ox, oy);
112
121
  px(ctx, hx + 14, hy + 10, 1, 1, PAL.bodyDeepShadow, s, ox, oy);
113
- // Head base (shadow layer)
114
- px(ctx, hx, hy, 14, 11, PAL.bodyDark, s, ox, oy);
115
- // Cut corners for rounded look
116
- px(ctx, hx, hy, 1, 1, 'transparent', s, ox, oy);
117
- px(ctx, hx + 13, hy, 1, 1, 'transparent', s, ox, oy);
118
- px(ctx, hx, hy + 10, 1, 1, 'transparent', s, ox, oy);
119
- px(ctx, hx + 13, hy + 10, 1, 1, 'transparent', s, ox, oy);
120
122
  // Head fill (inner area) — bodyMain
121
123
  px(ctx, hx + 1, hy + 1, 12, 9, PAL.bodyMain, s, ox, oy);
122
124
  // Top surface: bodyMidLight (facing light source)
@@ -141,14 +143,23 @@ function drawHead(ctx, s, ox, oy, eyeColor, mood, frame, headShiftX) {
141
143
  // (#9) Dreaming: eyes closed (flat line)
142
144
  const eyesClosed = mood === 'dreaming';
143
145
  const eyeH = fullBlink || eyesClosed ? 1 : halfBlink ? 2 : 3;
144
- // Eye glow background dimmed if dreaming
145
- const eyeC = mood === 'dreaming' ? dimColor(eyeColor.startsWith('rgb') ? '#4a6670' : eyeColor, 0.5) : eyeColor;
146
+ // Eye socketsdark recessed area around eyes for contrast (makes eyes pop from face)
147
+ if (!fullBlink && !eyesClosed) {
148
+ px(ctx, hx + 1, eyeY - 1, 6, eyeH + 2, PAL.bodyDeepShadow, s, ox, oy);
149
+ px(ctx, hx + 7, eyeY - 1, 6, eyeH + 2, PAL.bodyDeepShadow, s, ox, oy);
150
+ }
151
+ // Eye glow background — brighter white-green for alive look, dimmed if dreaming
152
+ const eyeC = mood === 'dreaming'
153
+ ? dimColor(eyeColor.startsWith('rgb') ? '#4a6670' : eyeColor, 0.5)
154
+ : '#80ffb0'; // bright cyan-green that contrasts against the green head
146
155
  px(ctx, hx + 2, eyeY, 4, eyeH, eyeC, s, ox, oy);
147
156
  px(ctx, hx + 8, eyeY, 4, eyeH, eyeC, s, ox, oy);
148
- // Specular highlights on eyes — makes them look glassy/alive (technique 8)
157
+ // Specular highlights on eyes — 2px L-shape catch-light for glassy/alive look (technique 8)
149
158
  if (!fullBlink && !eyesClosed) {
150
- px(ctx, hx + 2, eyeY, 1, 1, PAL.bodySpecular, s, ox, oy);
151
- px(ctx, hx + 8, eyeY, 1, 1, PAL.bodySpecular, s, ox, oy);
159
+ px(ctx, hx + 2, eyeY, 2, 1, PAL.white, s, ox, oy);
160
+ px(ctx, hx + 2, eyeY + 1, 1, 1, PAL.white, s, ox, oy);
161
+ px(ctx, hx + 8, eyeY, 2, 1, PAL.white, s, ox, oy);
162
+ px(ctx, hx + 8, eyeY + 1, 1, 1, PAL.white, s, ox, oy);
152
163
  }
153
164
  if (!fullBlink && !eyesClosed) {
154
165
  // Pupils — shift based on mood
@@ -301,8 +312,12 @@ function drawTorso(ctx, s, ox, oy, accentColor, mood, frame, bodyShiftY, torsoWi
301
312
  dither(ctx, 21, ty + 2, 1, 8, PAL.accentDark, PAL.bodyMain, s, ox, oy);
302
313
  // Specular highlight on chest panel frame (technique 8)
303
314
  px(ctx, 11, ty + 2, 1, 1, PAL.bodySpecular, s, ox, oy);
304
- // Chest display inner (8x6 dark)
305
- px(ctx, 12, ty + 3, 8, 6, PAL.black, s, ox, oy);
315
+ // Chest display inner (8x6) dark with subtle screen glow for readability
316
+ px(ctx, 12, ty + 3, 8, 6, '#0a1628', s, ox, oy);
317
+ // Scanline effect — subtle horizontal lines for CRT/screen feel
318
+ for (let scanY = 0; scanY < 6; scanY += 2) {
319
+ px(ctx, 12, ty + 3 + scanY, 8, 1, '#0d1e36', s, ox, oy);
320
+ }
306
321
  // Animated display content (now using 8x6 inner area)
307
322
  drawChestDisplay(ctx, s, ox, oy, 12, ty + 3, accentColor, mood, frame);
308
323
  }
@@ -310,13 +325,14 @@ function drawChestDisplay(ctx, s, ox, oy, dx, dy, color, mood, frame) {
310
325
  // Inner display area: 8x6 pixels
311
326
  const dimC = dimColor(color.startsWith('rgb') ? '#3fb950' : color, 0.3);
312
327
  if (mood === 'idle') {
313
- // Scrolling sine wave pattern across 8px width
328
+ // Scrolling sine wave pattern across 8px width — thicker (2px tall) for readability
329
+ const brightC = dimColor(color.startsWith('rgb') ? '#3fb950' : color, 1.0);
314
330
  for (let i = 0; i < 8; i++) {
315
331
  const waveY = Math.round(Math.sin((i + frame) * 0.8) * 2) + 2;
316
- px(ctx, dx + i, dy + waveY, 1, 1, color, s, ox, oy);
317
- // Dimmer trail below
318
- if (waveY + 1 < 6)
319
- px(ctx, dx + i, dy + waveY + 1, 1, 1, dimC, s, ox, oy);
332
+ px(ctx, dx + i, dy + waveY, 1, 2, brightC, s, ox, oy);
333
+ // Glow trail above wave
334
+ if (waveY - 1 >= 0)
335
+ px(ctx, dx + i, dy + waveY - 1, 1, 1, dimC, s, ox, oy);
320
336
  }
321
337
  }
322
338
  else if (mood === 'talking') {
@@ -737,10 +753,8 @@ export function drawRobot(ctx, x, y, scale, mood, frame, moodColor, weather, isW
737
753
  headShiftX += (frame % 6 < 3) ? 1 : 0;
738
754
  }
739
755
  const armPose = isWalking ? getWalkingArmPose(walkPhase || 0) : getArmPose(mood, frame);
740
- // ── Clear the bounding area ──
741
- ctx.clearRect(x - 12 * s + weatherShakeX * s, y - 4 * s, 56 * s, 56 * s);
742
- // Also clear without shake to avoid artifacts
743
- ctx.clearRect(x - 12 * s, y - 4 * s, 56 * s, 56 * s);
756
+ // NOTE: clearRect removed — it was wiping the background behind the robot to white/transparent
757
+ // The robot is drawn ON TOP of the world, it should not clear anything beneath it
744
758
  // Apply weather shake offset
745
759
  const drawX = x + weatherShakeX * s;
746
760
  // ── Drop Shadow (technique 10: dark blue-green, not pure black) ──
@@ -356,8 +356,8 @@ export function tickStreamBrain(brain, frame) {
356
356
  }
357
357
  brain.activeCapabilities = [...new Set(brain.activeCapabilities)];
358
358
  }
359
- // Every 300 frames (~50 seconds): suggest a tool action if appropriate
360
- if (frame - brain.lastSuggestionFrame >= 300) {
359
+ // Every 120 frames (~20 seconds): suggest a tool action if appropriate
360
+ if (frame - brain.lastSuggestionFrame >= 120) {
361
361
  brain.lastSuggestionFrame = frame;
362
362
  const suggestion = suggestToolAction(brain);
363
363
  if (suggestion) {
@@ -370,8 +370,8 @@ export function tickStreamBrain(brain, frame) {
370
370
  };
371
371
  }
372
372
  }
373
- // Every 600 frames (~100 seconds): generate cross-domain insight if possible
374
- if (frame - brain.lastInsightFrame >= 600) {
373
+ // Every 240 frames (~40 seconds): generate cross-domain insight if possible
374
+ if (frame - brain.lastInsightFrame >= 240) {
375
375
  brain.lastInsightFrame = frame;
376
376
  const relevantDomains = Object.entries(brain.domainGraph)
377
377
  .filter(([, n]) => n.relevance >= 0.3)
@@ -0,0 +1,2 @@
1
+ export declare function registerStreamControlTools(): void;
2
+ //# sourceMappingURL=stream-control.d.ts.map