shadok-ai 0.8.21 → 0.8.23

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 (2) hide show
  1. package/package.json +1 -1
  2. package/public/index.html +58 -48
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadok-ai",
3
- "version": "0.8.21",
3
+ "version": "0.8.23",
4
4
  "main": "dist/session.js",
5
5
  "scripts": {
6
6
  "test": "node --import tsx --test test/*.ts context/*/test/*.test.mjs",
package/public/index.html CHANGED
@@ -11,7 +11,7 @@
11
11
  <title>shadok-ai — cockpit</title>
12
12
  <!-- The idle favicon: a resting Shadok. paint() swaps in the pumping / "!" / "?"
13
13
  variants once the JS runs; this is only the pre-script icon. -->
14
- <link rel="icon" id="favicon" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Crect%20width%3D%2232%22%20height%3D%2232%22%20rx%3D%227%22%20fill%3D%22%2314161d%22%2F%3E%3Cg%20fill%3D%22%23f0a848%22%3E%3Crect%20x%3D%2211.4%22%20y%3D%2221%22%20width%3D%221.7%22%20height%3D%229%22%20rx%3D%220.85%22%2F%3E%3Crect%20x%3D%2217.4%22%20y%3D%2221%22%20width%3D%221.7%22%20height%3D%229%22%20rx%3D%220.85%22%2F%3E%3Crect%20x%3D%229.2%22%20y%3D%2228.7%22%20width%3D%224.6%22%20height%3D%221.7%22%20rx%3D%220.85%22%2F%3E%3Crect%20x%3D%2216.4%22%20y%3D%2228.7%22%20width%3D%224.6%22%20height%3D%221.7%22%20rx%3D%220.85%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23f0a848%22%3E%3Cellipse%20cx%3D%2215%22%20cy%3D%2216.8%22%20rx%3D%227.4%22%20ry%3D%227.6%22%2F%3E%3Cg%20transform%3D%22rotate(6%2019.6%2015.6)%22%3E%3Crect%20x%3D%2218.6%22%20y%3D%2215%22%20width%3D%222.1%22%20height%3D%228.4%22%20rx%3D%221.05%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M14.6%2010%20C%2014.6%206.6%2C%2016.6%204.8%2C%2018.9%204.8%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%223%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%2F%3E%3Ccircle%20cx%3D%2219.5%22%20cy%3D%224.7%22%20r%3D%223%22%2F%3E%3Cpath%20d%3D%22M22.1%203.5%20L26.4%205%20L22.1%206.5%20Z%22%2F%3E%3Ccircle%20cx%3D%2220.2%22%20cy%3D%224.2%22%20r%3D%220.95%22%20fill%3D%22%2314161d%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E">
14
+ <link rel="icon" id="favicon" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Crect%20width%3D%2232%22%20height%3D%2232%22%20rx%3D%227%22%20fill%3D%22%2314161d%22%2F%3E%3Cg%20fill%3D%22%23f0a848%22%3E%3Crect%20x%3D%2212%22%20y%3D%2224%22%20width%3D%221.9%22%20height%3D%227%22%20rx%3D%220.95%22%2F%3E%3Crect%20x%3D%2216.1%22%20y%3D%2224%22%20width%3D%221.9%22%20height%3D%227%22%20rx%3D%220.95%22%2F%3E%3Crect%20x%3D%229.8%22%20y%3D%2229.8%22%20width%3D%224.8%22%20height%3D%221.9%22%20rx%3D%220.95%22%2F%3E%3Crect%20x%3D%2215.4%22%20y%3D%2229.8%22%20width%3D%224.8%22%20height%3D%221.9%22%20rx%3D%220.95%22%2F%3E%3C%2Fg%3E%3Cg%3E%3Cellipse%20cx%3D%227.7%22%20cy%3D%2219.5%22%20rx%3D%222.1%22%20ry%3D%223.5%22%20fill%3D%22%23f0a848%22%20transform%3D%22rotate(-16%207.7%2019.5)%22%2F%3E%3Cellipse%20cx%3D%2222.3%22%20cy%3D%2219.5%22%20rx%3D%222.1%22%20ry%3D%223.5%22%20fill%3D%22%23f0a848%22%20transform%3D%22rotate(16%2022.3%2019.5)%22%2F%3E%3Cellipse%20cx%3D%2215%22%20cy%3D%2219.5%22%20rx%3D%227.8%22%20ry%3D%228.2%22%20fill%3D%22%23f0a848%22%2F%3E%3Crect%20x%3D%2213.4%22%20y%3D%228%22%20width%3D%223.2%22%20height%3D%225%22%20rx%3D%221.6%22%20fill%3D%22%23f0a848%22%2F%3E%3Ccircle%20cx%3D%2215%22%20cy%3D%226.2%22%20r%3D%224.3%22%20fill%3D%22%23f0a848%22%2F%3E%3Cpath%20d%3D%22M13.6%209.8%20L16.4%209.8%20L15%2011.8%20Z%22%20fill%3D%22%23f0a848%22%2F%3E%3Ccircle%20cx%3D%2213.1%22%20cy%3D%226%22%20r%3D%222%22%20fill%3D%22%23fff%22%2F%3E%3Ccircle%20cx%3D%2216.9%22%20cy%3D%226%22%20r%3D%222%22%20fill%3D%22%23fff%22%2F%3E%3Ccircle%20cx%3D%2213.1%22%20cy%3D%226.1%22%20r%3D%221.1%22%20fill%3D%22%2314161d%22%2F%3E%3Ccircle%20cx%3D%2216.9%22%20cy%3D%226.1%22%20r%3D%221.1%22%20fill%3D%22%2314161d%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E">
15
15
  <style>
16
16
  :root {
17
17
  --bg: #14161d;
@@ -1019,17 +1019,15 @@
1019
1019
  /* The pumping Shadok: `color` feeds its `currentColor` fill so it follows the
1020
1020
  palette. The body bobs and the arm swings — the pump — on the same beat. */
1021
1021
  #thinking .tw-shadok { display: inline-flex; color: var(--amber); }
1022
- #thinking .tw-shadok svg { width: 20px; height: 20px; overflow: visible; }
1023
- /* Body bobs with translate (no transform-origin needed that unit is a
1024
- cross-browser trap on SVG). The arm swings from its own top via fill-box, so
1025
- it reads as working a pump handle. */
1026
- #thinking .tw-shadok .sh-body { animation: tw-pump 0.7s ease-in-out infinite; }
1027
- #thinking .tw-shadok .sh-arm { animation: tw-arm 0.7s ease-in-out infinite; transform-box: fill-box; transform-origin: top center; }
1028
- @keyframes tw-pump { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(1.5px); } }
1029
- @keyframes tw-arm { 0%, 100% { transform: rotate(-10deg); } 50% { transform: rotate(28deg); } }
1022
+ #thinking .tw-shadok svg { width: 22px; height: 22px; overflow: visible; }
1023
+ /* The whole Shadok (body + arm + handle) bobs with translate — no
1024
+ transform-origin, which is a cross-browser trap on SVG while the pump rod
1025
+ and legs stay planted, so the handle strokes up and down the rod. */
1026
+ #thinking .tw-shadok .sh-bob { animation: tw-bob 0.55s ease-in-out infinite; }
1027
+ @keyframes tw-bob { 0%, 100% { transform: translateY(-1.8px); } 50% { transform: translateY(2.2px); } }
1030
1028
  @media (prefers-reduced-motion: reduce) {
1031
1029
  #thinking .tw-text { animation: none; color: var(--phosphor); -webkit-text-fill-color: currentColor; }
1032
- #thinking .tw-shadok .sh-body, #thinking .tw-shadok .sh-arm { animation: none; }
1030
+ #thinking .tw-shadok .sh-bob { animation: none; }
1033
1031
  }
1034
1032
 
1035
1033
  /* Composer */
@@ -3167,34 +3165,52 @@
3167
3165
  const v = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
3168
3166
  return v || fallback;
3169
3167
  }
3170
- /** The Shadok itself — the cockpit's mascot, which famously PUMPS. One drawing
3171
- * serves every use: the favicon states here and the in-page "pumping"
3172
- * indicator. `dx` shifts it left to clear room for a "!" / "?"; `bob`/`armRot`
3173
- * pose a single frame of the pump (the favicon animates by re-generating with
3174
- * new values, like the old spinner did); `anim` instead tags the body and arm
3175
- * groups so CSS can drive them (used only in the DOM indicator, never a data
3176
- * URI — CSS animation inside a favicon is unreliable). Legs stay planted. */
3177
- function shadokInner(fill, { dx = 0, bob = 0, armRot = 6, anim = false } = {}) {
3168
+ /** The Shadok itself — the cockpit's mascot, which famously PUMPS. Drawn
3169
+ * FRONT-ON: a plump round body, a short neck, a round head with two big googly
3170
+ * eyes (their signature a side profile with a long beak read as a dinosaur),
3171
+ * a tiny beak, two stub wings, two long legs. One drawing serves every use.
3172
+ * `bob` poses one frame of the pump (the favicon animates by re-generating);
3173
+ * `anim` instead tags the bobbing group so CSS drives it (the DOM indicator
3174
+ * only — CSS animation inside a favicon data URI is unreliable). `pump` adds a
3175
+ * FIXED rod on the right the Shadok works with its wing; that steady reference,
3176
+ * with the planted legs, is what makes the bob read at favicon size. `sym`
3177
+ * stamps a bold "!" / "?" over the belly, outlined in the ground colour so the
3178
+ * accent-on-accent "?" still reads (the eyes stay clear above it). Legs (and,
3179
+ * pumping, the rod) stay planted; the body/head/wings bob. The Shadok shifts a
3180
+ * little left when pumping, to seat the rod on its right. Eyes are always
3181
+ * white + dark, never the accent, so they read on any `fill`. */
3182
+ function shadokInner(fill, { bob = 0, pump = false, anim = false, sym = null, symColor } = {}) {
3178
3183
  const base = themeColor("--bg", "#14161d");
3179
- const bodyCls = anim ? ' class="sh-body"' : "";
3180
- const armCls = anim ? ' class="sh-arm"' : "";
3181
- const bodyTf = anim ? "" : ` transform="translate(0 ${bob})"`;
3182
- const armTf = anim ? "" : ` transform="rotate(${armRot} 19.6 15.6)"`;
3184
+ const hx = pump ? 13.6 : 15; // body/head centre X
3185
+ const hy = 6.2; // head centre Y
3186
+ const bobCls = anim ? ' class="sh-bob"' : "";
3187
+ const bobTf = anim ? "" : ` transform="translate(0 ${bob})"`;
3188
+ // The right wing rests low, or — pumping — angles up to work the rod's handle.
3189
+ const rWing = pump
3190
+ ? `<ellipse cx="${hx + 7.6}" cy="17.8" rx="2.1" ry="3.4" fill="${fill}" transform="rotate(28 ${hx + 7.6} 17.8)"/>`
3191
+ : `<ellipse cx="${hx + 7.3}" cy="19.5" rx="2.1" ry="3.5" fill="${fill}" transform="rotate(16 ${hx + 7.3} 19.5)"/>`;
3192
+ const rod = pump ? `<rect x="23.4" y="15.5" width="1.5" height="13.7" rx="0.6" fill="${fill}"/>` : "";
3193
+ const glyph = sym
3194
+ ? `<text x="${hx}" y="22" font-family="monospace" font-size="15.5" font-weight="800" fill="${symColor || fill}" stroke="${base}" stroke-width="2.6" paint-order="stroke" text-anchor="middle">${sym}</text>`
3195
+ : "";
3183
3196
  return (
3184
- `<g transform="translate(${dx} 0)">` +
3197
+ rod +
3185
3198
  // legs + feet (planted, not part of the bob)
3186
3199
  `<g fill="${fill}">` +
3187
- `<rect x="11.4" y="21" width="1.7" height="9" rx="0.85"/><rect x="17.4" y="21" width="1.7" height="9" rx="0.85"/>` +
3188
- `<rect x="9.2" y="28.7" width="4.6" height="1.7" rx="0.85"/><rect x="16.4" y="28.7" width="4.6" height="1.7" rx="0.85"/>` +
3200
+ `<rect x="${hx - 3}" y="24" width="1.9" height="7" rx="0.95"/><rect x="${hx + 1.1}" y="24" width="1.9" height="7" rx="0.95"/>` +
3201
+ `<rect x="${hx - 5.2}" y="29.8" width="4.8" height="1.9" rx="0.95"/><rect x="${hx + 0.4}" y="29.8" width="4.8" height="1.9" rx="0.95"/>` +
3202
+ `</g>` +
3203
+ // wings + body + neck + head + beak + two eyes — all bob together
3204
+ `<g${bobCls}${bobTf}>` +
3205
+ `<ellipse cx="${hx - 7.3}" cy="19.5" rx="2.1" ry="3.5" fill="${fill}" transform="rotate(-16 ${hx - 7.3} 19.5)"/>${rWing}` +
3206
+ `<ellipse cx="${hx}" cy="19.5" rx="7.8" ry="8.2" fill="${fill}"/>` +
3207
+ `<rect x="${hx - 1.6}" y="8" width="3.2" height="5" rx="1.6" fill="${fill}"/>` +
3208
+ `<circle cx="${hx}" cy="${hy}" r="4.3" fill="${fill}"/>` +
3209
+ `<path d="M${hx - 1.4} ${hy + 3.6} L${hx + 1.4} ${hy + 3.6} L${hx} ${hy + 5.6} Z" fill="${fill}"/>` +
3210
+ `<circle cx="${hx - 1.9}" cy="${hy - 0.2}" r="2" fill="#fff"/><circle cx="${hx + 1.9}" cy="${hy - 0.2}" r="2" fill="#fff"/>` +
3211
+ `<circle cx="${hx - 1.9}" cy="${hy - 0.1}" r="1.1" fill="${base}"/><circle cx="${hx + 1.9}" cy="${hy - 0.1}" r="1.1" fill="${base}"/>` +
3189
3212
  `</g>` +
3190
- // body + pumping arm + long neck + head + beak + eye
3191
- `<g${bodyCls} fill="${fill}"${bodyTf}>` +
3192
- `<ellipse cx="15" cy="16.8" rx="7.4" ry="7.6"/>` +
3193
- `<g${armCls}${armTf}><rect x="18.6" y="15" width="2.1" height="8.4" rx="1.05"/></g>` +
3194
- `<path d="M14.6 10 C 14.6 6.6, 16.6 4.8, 18.9 4.8" stroke="${fill}" stroke-width="3" fill="none" stroke-linecap="round"/>` +
3195
- `<circle cx="19.5" cy="4.7" r="3"/><path d="M22.1 3.5 L26.4 5 L22.1 6.5 Z"/>` +
3196
- `<circle cx="20.2" cy="4.2" r="0.95" fill="${base}"/>` +
3197
- `</g></g>`
3213
+ glyph
3198
3214
  );
3199
3215
  }
3200
3216
  function faviconWrap(inner) {
@@ -3207,27 +3223,21 @@
3207
3223
  )
3208
3224
  );
3209
3225
  }
3210
- /** The favicon: an accent Shadok on the dark ground. A waiting state adds a
3211
- * bold "!" (something to answer) or "?" (something to read) in its colour, and
3212
- * the Shadok slides left to make room — the coloured glyph is what the user
3213
- * asked to distinguish the two. No symbol → the idle Shadok. */
3226
+ /** The favicon: an accent Shadok on the dark ground. A waiting state stamps a
3227
+ * bold "!" (something to answer) or "?" (something to read) OVER it, in its
3228
+ * colour. No symbol the idle Shadok. */
3214
3229
  function faviconSVG(symbol, symColor) {
3215
3230
  const accent = themeColor("--amber", "#f0a848");
3216
- const shadok = shadokInner(accent, symbol ? { dx: -3.6 } : {});
3217
- const sym = symbol
3218
- ? `<text x="25.8" y="13" font-family="monospace" font-size="15" font-weight="800" fill="${symColor || accent}" text-anchor="middle">${symbol}</text>`
3219
- : "";
3220
- return faviconWrap(shadok + sym);
3231
+ return faviconWrap(shadokInner(accent, symbol ? { sym: symbol, symColor } : {}));
3221
3232
  }
3222
- /** The "working" favicon: the Shadok pumping. `phase` (0..PUMP_FRAMES-1) rides
3223
- * a cycle the body bobs and the arm swings, re-generated each tick. */
3233
+ /** The "working" favicon: the Shadok pumping. `phase` (0..PUMP_FRAMES-1) rides a
3234
+ * cycle; the whole Shadok heaves up and down against the fixed rod. */
3224
3235
  const PUMP_FRAMES = 8;
3225
3236
  function faviconPumpingSVG(phase) {
3226
3237
  const accent = themeColor("--amber", "#f0a848");
3227
3238
  const p = (Math.sin((phase / PUMP_FRAMES) * 2 * Math.PI - Math.PI / 2) + 1) / 2; // 0..1..0
3228
- const bob = +(p * 1.8).toFixed(2);
3229
- const armRot = Math.round(-8 + p * 32); // -8 (up) .. +24 (down)
3230
- return faviconWrap(shadokInner(accent, { bob, armRot }));
3239
+ const bob = +(-2 + p * 4.4).toFixed(2); // -2 (up) .. +2.4 (down): a big, visible stroke
3240
+ return faviconWrap(shadokInner(accent, { bob, pump: true }));
3231
3241
  }
3232
3242
  /** What each channel is asking for, as the pure module wants it. */
3233
3243
  function attentionInput() {
@@ -3299,7 +3309,7 @@
3299
3309
  const twShadok = document.querySelector("#thinking .tw-shadok");
3300
3310
  if (twShadok)
3301
3311
  twShadok.innerHTML =
3302
- `<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">${shadokInner("currentColor", { anim: true })}</svg>`;
3312
+ `<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">${shadokInner("currentColor", { pump: true, anim: true })}</svg>`;
3303
3313
  }
3304
3314
  // Coming back must stop the blink at once, not at the next tick. Both signals
3305
3315
  // matter: switching tabs fires visibilitychange, switching application only