shadok-ai 0.8.26 → 0.8.27
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 +1 -1
- package/public/index.html +74 -62
package/package.json
CHANGED
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%
|
|
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%3Cline%20x1%3D%2210.8%22%20y1%3D%2223%22%20x2%3D%2210.4%22%20y2%3D%2230.6%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%221.3%22%20stroke-linecap%3D%22round%22%2F%3E%3Cline%20x1%3D%2216.400000000000002%22%20y1%3D%2223%22%20x2%3D%2216.8%22%20y2%3D%2230.6%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%221.3%22%20stroke-linecap%3D%22round%22%2F%3E%3Cline%20x1%3D%228.8%22%20y1%3D%2230.7%22%20x2%3D%2211.9%22%20y2%3D%2230.7%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%221.3%22%20stroke-linecap%3D%22round%22%2F%3E%3Cline%20x1%3D%2215.4%22%20y1%3D%2230.7%22%20x2%3D%2218.5%22%20y2%3D%2230.7%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%221.3%22%20stroke-linecap%3D%22round%22%2F%3E%3Cline%20x1%3D%2219.6%22%20y1%3D%2217.2%22%20x2%3D%2224.000000000000004%22%20y2%3D%2220.4%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%221.3%22%20stroke-linecap%3D%22round%22%2F%3E%3Cg%3E%3Cline%20x1%3D%2211.600000000000001%22%20y1%3D%225.399999999999999%22%20x2%3D%229.600000000000001%22%20y2%3D%222.8%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%220.9%22%20stroke-linecap%3D%22round%22%2F%3E%3Ccircle%20cx%3D%229.600000000000001%22%20cy%3D%222.8%22%20r%3D%221%22%20fill%3D%22%23f0a848%22%2F%3E%3Cline%20x1%3D%2216%22%20y1%3D%225.399999999999999%22%20x2%3D%2218%22%20y2%3D%222.8%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%220.9%22%20stroke-linecap%3D%22round%22%2F%3E%3Ccircle%20cx%3D%2218%22%20cy%3D%222.8%22%20r%3D%221%22%20fill%3D%22%23f0a848%22%2F%3E%3Ccircle%20cx%3D%2213.8%22%20cy%3D%2216.2%22%20r%3D%228.4%22%20fill%3D%22%23f0a848%22%2F%3E%3Cpath%20d%3D%22M12.200000000000001%2018.2%20L15.4%2018.2%20L13.8%2021.6%20Z%22%20fill%3D%22%23f0a848%22%2F%3E%3Ccircle%20cx%3D%2210.9%22%20cy%3D%227.799999999999999%22%20r%3D%222.6%22%20fill%3D%22%23fff%22%2F%3E%3Ccircle%20cx%3D%2216.7%22%20cy%3D%227.799999999999999%22%20r%3D%222.6%22%20fill%3D%22%23fff%22%2F%3E%3Ccircle%20cx%3D%2211.200000000000001%22%20cy%3D%228.1%22%20r%3D%221.3%22%20fill%3D%22%2314161d%22%2F%3E%3Ccircle%20cx%3D%2217%22%20cy%3D%228.1%22%20r%3D%221.3%22%20fill%3D%22%2314161d%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E">
|
|
15
15
|
<style>
|
|
16
16
|
:root {
|
|
17
17
|
--bg: #14161d;
|
|
@@ -1017,17 +1017,12 @@
|
|
|
1017
1017
|
}
|
|
1018
1018
|
@keyframes tw-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
|
|
1019
1019
|
/* The pumping Shadok: `color` feeds its `currentColor` fill so it follows the
|
|
1020
|
-
palette.
|
|
1020
|
+
palette. It is animated by re-drawing in JS (renderTw), not CSS — the pump's
|
|
1021
|
+
arm has to be re-linked to the lever each frame. */
|
|
1021
1022
|
#thinking .tw-shadok { display: inline-flex; color: var(--amber); }
|
|
1022
1023
|
#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); } }
|
|
1028
1024
|
@media (prefers-reduced-motion: reduce) {
|
|
1029
1025
|
#thinking .tw-text { animation: none; color: var(--phosphor); -webkit-text-fill-color: currentColor; }
|
|
1030
|
-
#thinking .tw-shadok .sh-bob { animation: none; }
|
|
1031
1026
|
}
|
|
1032
1027
|
|
|
1033
1028
|
/* Composer */
|
|
@@ -3241,50 +3236,53 @@
|
|
|
3241
3236
|
const v = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
3242
3237
|
return v || fallback;
|
|
3243
3238
|
}
|
|
3244
|
-
/** The Shadok itself — the cockpit's mascot, which famously PUMPS. Drawn
|
|
3245
|
-
*
|
|
3246
|
-
*
|
|
3247
|
-
*
|
|
3248
|
-
*
|
|
3249
|
-
*
|
|
3250
|
-
*
|
|
3251
|
-
*
|
|
3252
|
-
*
|
|
3253
|
-
*
|
|
3254
|
-
*
|
|
3255
|
-
*
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
function shadokInner(fill, { bob = 0, pump = false, anim = false, sym = null, symColor } = {}) {
|
|
3239
|
+
/** The Shadok itself — the cockpit's mascot, which famously PUMPS. Drawn like
|
|
3240
|
+
* the real thing (Rouxel): a round BALL body, two big googly eyes perched on
|
|
3241
|
+
* top, two antennae, a tiny beak, thin stick legs. One drawing serves every
|
|
3242
|
+
* state. `lever` (degrees around the fulcrum) poses the see-saw hand-pump it
|
|
3243
|
+
* works — pass a number to show the pump, null for the idle stub arm; `bob`
|
|
3244
|
+
* dips the ball with the effort. The arm is recomputed each call from the
|
|
3245
|
+
* (bobbed) shoulder to the lever end it grips, so the linkage is always right —
|
|
3246
|
+
* animating the arm with CSS instead made it swing around the pivot, backwards.
|
|
3247
|
+
* `sym` stamps a bold "!" / "?" over the ball, outlined in the ground colour so
|
|
3248
|
+
* the accent-on-accent "?" still reads (eyes stay clear above it). Legs and the
|
|
3249
|
+
* fulcrum stay planted. Eyes are always white + dark, never the accent, so they
|
|
3250
|
+
* read on any `fill` (the `currentColor` indicator included). */
|
|
3251
|
+
const PX = 23.2, PY = 24.4; // the pump lever's fulcrum
|
|
3252
|
+
function shadokInner(fill, { lever = null, bob = 0, sym = null, symColor } = {}) {
|
|
3259
3253
|
const base = themeColor("--bg", "#14161d");
|
|
3260
|
-
const
|
|
3261
|
-
const
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3254
|
+
const cx = 13.8, cy = 16.2, r = 8.4, eyeY = cy - 8.4, eyeSep = 5.8, eyeR = 2.6, pupR = 1.3;
|
|
3255
|
+
const shX = cx + r - 2.6, shY = cy + 1.8 + bob; // shoulder (moves with the bob)
|
|
3256
|
+
let fulcrum = "", leverEl = "", armEl = "";
|
|
3257
|
+
if (lever !== null) {
|
|
3258
|
+
const rad = (lever * Math.PI) / 180, nearX = PX - 6.5, farX = PX + 5;
|
|
3259
|
+
const ax = PX + (nearX - PX) * Math.cos(rad), ay = PY + (nearX - PX) * Math.sin(rad);
|
|
3260
|
+
const bx = PX + (farX - PX) * Math.cos(rad), by = PY + (farX - PX) * Math.sin(rad);
|
|
3261
|
+
fulcrum = `<path d="M${PX - 2.2} 29 L${PX + 2.2} 29 L${PX} ${PY} Z" fill="${fill}"/>`;
|
|
3262
|
+
leverEl = `<line x1="${ax}" y1="${ay}" x2="${bx}" y2="${by}" stroke="${fill}" stroke-width="1.7" stroke-linecap="round"/>`;
|
|
3263
|
+
armEl = `<line x1="${shX}" y1="${shY}" x2="${ax}" y2="${ay}" stroke="${fill}" stroke-width="1.3" stroke-linecap="round"/>`;
|
|
3264
|
+
} else {
|
|
3265
|
+
armEl = `<line x1="${shX}" y1="${cy + 1 + bob}" x2="${cx + r + 1.8}" y2="${cy + 4.2 + bob}" stroke="${fill}" stroke-width="1.3" stroke-linecap="round"/>`;
|
|
3266
|
+
}
|
|
3269
3267
|
const glyph = sym
|
|
3270
|
-
? `<text x="${
|
|
3268
|
+
? `<text x="${cx}" y="${cy + 3.4 + bob}" font-family="ui-monospace, monospace" font-size="14" font-weight="800" fill="${symColor || fill}" stroke="${base}" stroke-width="2.4" paint-order="stroke" text-anchor="middle">${sym}</text>`
|
|
3271
3269
|
: "";
|
|
3272
3270
|
return (
|
|
3273
|
-
|
|
3274
|
-
// legs + feet (planted
|
|
3275
|
-
`<
|
|
3276
|
-
`<
|
|
3277
|
-
`<
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
`<
|
|
3282
|
-
`<
|
|
3283
|
-
`<
|
|
3284
|
-
`<circle cx="${
|
|
3285
|
-
`<path d="M${
|
|
3286
|
-
`<circle cx="${
|
|
3287
|
-
`<circle cx="${
|
|
3271
|
+
fulcrum + leverEl +
|
|
3272
|
+
// thin legs + feet (planted)
|
|
3273
|
+
`<line x1="${cx - 3}" y1="${cy + r - 1.6}" x2="${cx - 3.4}" y2="30.6" stroke="${fill}" stroke-width="1.3" stroke-linecap="round"/>` +
|
|
3274
|
+
`<line x1="${cx + 2.6}" y1="${cy + r - 1.6}" x2="${cx + 3}" y2="30.6" stroke="${fill}" stroke-width="1.3" stroke-linecap="round"/>` +
|
|
3275
|
+
`<line x1="${cx - 5}" y1="30.7" x2="${cx - 1.9}" y2="30.7" stroke="${fill}" stroke-width="1.3" stroke-linecap="round"/>` +
|
|
3276
|
+
`<line x1="${cx + 1.6}" y1="30.7" x2="${cx + 4.7}" y2="30.7" stroke="${fill}" stroke-width="1.3" stroke-linecap="round"/>` +
|
|
3277
|
+
armEl +
|
|
3278
|
+
// ball body + antennae + beak + eyes — bob together with the effort
|
|
3279
|
+
`<g transform="translate(0 ${bob})">` +
|
|
3280
|
+
`<line x1="${cx - 2.2}" y1="${eyeY - 2.4}" x2="${cx - 4.2}" y2="2.8" stroke="${fill}" stroke-width="0.9" stroke-linecap="round"/><circle cx="${cx - 4.2}" cy="2.8" r="1" fill="${fill}"/>` +
|
|
3281
|
+
`<line x1="${cx + 2.2}" y1="${eyeY - 2.4}" x2="${cx + 4.2}" y2="2.8" stroke="${fill}" stroke-width="0.9" stroke-linecap="round"/><circle cx="${cx + 4.2}" cy="2.8" r="1" fill="${fill}"/>` +
|
|
3282
|
+
`<circle cx="${cx}" cy="${cy}" r="${r}" fill="${fill}"/>` +
|
|
3283
|
+
`<path d="M${cx - 1.6} ${cy + 2} L${cx + 1.6} ${cy + 2} L${cx} ${cy + 5.4} Z" fill="${fill}"/>` +
|
|
3284
|
+
`<circle cx="${cx - eyeSep / 2}" cy="${eyeY}" r="${eyeR}" fill="#fff"/><circle cx="${cx + eyeSep / 2}" cy="${eyeY}" r="${eyeR}" fill="#fff"/>` +
|
|
3285
|
+
`<circle cx="${cx - eyeSep / 2 + 0.3}" cy="${eyeY + 0.3}" r="${pupR}" fill="${base}"/><circle cx="${cx + eyeSep / 2 + 0.3}" cy="${eyeY + 0.3}" r="${pupR}" fill="${base}"/>` +
|
|
3288
3286
|
`</g>` +
|
|
3289
3287
|
glyph
|
|
3290
3288
|
);
|
|
@@ -3306,14 +3304,16 @@
|
|
|
3306
3304
|
const accent = themeColor("--amber", "#f0a848");
|
|
3307
3305
|
return faviconWrap(shadokInner(accent, symbol ? { sym: symbol, symColor } : {}));
|
|
3308
3306
|
}
|
|
3309
|
-
/** The
|
|
3310
|
-
*
|
|
3311
|
-
|
|
3307
|
+
/** The pump pose for a phase p (0..1..0): the Shadok pushes the lever DOWN (near
|
|
3308
|
+
* end down = negative angle) and the ball dips with the effort — shared by the
|
|
3309
|
+
* favicon and the in-page indicator so both pump the same way. */
|
|
3310
|
+
function pumpPose(p) { return { lever: 13 - p * 28, bob: +(p * 1.5).toFixed(2) }; }
|
|
3311
|
+
/** The "working" favicon: the Shadok pumping its lever. `phase` rides a cycle. */
|
|
3312
|
+
const PUMP_FRAMES = 12;
|
|
3312
3313
|
function faviconPumpingSVG(phase) {
|
|
3313
3314
|
const accent = themeColor("--amber", "#f0a848");
|
|
3314
3315
|
const p = (Math.sin((phase / PUMP_FRAMES) * 2 * Math.PI - Math.PI / 2) + 1) / 2; // 0..1..0
|
|
3315
|
-
|
|
3316
|
-
return faviconWrap(shadokInner(accent, { bob, pump: true }));
|
|
3316
|
+
return faviconWrap(shadokInner(accent, pumpPose(p)));
|
|
3317
3317
|
}
|
|
3318
3318
|
/** What each channel is asking for, as the pure module wants it. */
|
|
3319
3319
|
function attentionInput() {
|
|
@@ -3377,15 +3377,27 @@
|
|
|
3377
3377
|
}
|
|
3378
3378
|
}
|
|
3379
3379
|
function refreshBadge() { paint(); }
|
|
3380
|
-
// The in-page "pumping"
|
|
3381
|
-
//
|
|
3382
|
-
//
|
|
3383
|
-
//
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3380
|
+
// The in-page "Shadok is pumping" indicator uses the SAME `shadokInner`, tinted
|
|
3381
|
+
// via `currentColor` so it follows the palette. It animates by RE-DRAWING each
|
|
3382
|
+
// frame (like the favicon), not CSS: the pump's arm must be re-linked to the
|
|
3383
|
+
// lever every frame. A single heartbeat re-draws only while the indicator is
|
|
3384
|
+
// visible (it shows only during a turn), so an idle cockpit pays almost nothing.
|
|
3385
|
+
const twShadok = document.querySelector("#thinking .tw-shadok");
|
|
3386
|
+
const thinkingEl = document.getElementById("thinking");
|
|
3387
|
+
function renderTw(p) {
|
|
3388
|
+
if (!twShadok) return;
|
|
3389
|
+
const { lever, bob } = pumpPose(p);
|
|
3390
|
+
twShadok.innerHTML =
|
|
3391
|
+
`<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">${shadokInner("currentColor", { lever, bob })}</svg>`;
|
|
3392
|
+
}
|
|
3393
|
+
renderTw(0); // populate immediately so it isn't blank on first show
|
|
3394
|
+
if (!(window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches)) {
|
|
3395
|
+
let twPhase = 0;
|
|
3396
|
+
setInterval(() => {
|
|
3397
|
+
if (!thinkingEl || !thinkingEl.classList.contains("visible")) return;
|
|
3398
|
+
twPhase = (twPhase + 1) % PUMP_FRAMES;
|
|
3399
|
+
renderTw((Math.sin((twPhase / PUMP_FRAMES) * 2 * Math.PI - Math.PI / 2) + 1) / 2);
|
|
3400
|
+
}, 95);
|
|
3389
3401
|
}
|
|
3390
3402
|
// Coming back must stop the blink at once, not at the next tick. Both signals
|
|
3391
3403
|
// matter: switching tabs fires visibilitychange, switching application only
|