From 747f15ff805d4ea112804c8cf9b5494bdf5d7524 Mon Sep 17 00:00:00 2001 From: Wintermute <016967d974c3ac2859b738b1bb00747700a175518081d9aeb139f214c86eee6f@buzz.block.builderlab.xyz> Date: Sun, 23 Aug 2026 21:08:23 -0400 Subject: [PATCH] Mesh Buddy: procedural monochrome eyes replace the emoji face MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cozmo/Vector-style expression rig inspired by ggldnl's Procedural-Expression-Library: one parameter set (size, radius, lid rise, vertical offset, gaze) eased toward the active expression every frame, so mood changes, blinks, and idle gaze drift are all smooth morphs of the same rounded-rect eyes. Lower-lid ellipse masks carve the happy squint crescents. Moods map to runtime state: sleeping (mesh off, slow breathing bob), waking (starting), neutral (serving idle: blinks + gaze drift), happy (requests in flight), tired (failed). Drawn in the theme foreground on the theme background — monochrome by construction. Co-authored-by: Thomas Petersen Signed-off-by: Thomas Petersen --- desktop/public/mesh-buddy.html | 161 +++++++++++++++++++++++++++++++-- 1 file changed, 152 insertions(+), 9 deletions(-) diff --git a/desktop/public/mesh-buddy.html b/desktop/public/mesh-buddy.html index 890cab47f8..853c18ce8d 100644 --- a/desktop/public/mesh-buddy.html +++ b/desktop/public/mesh-buddy.html @@ -10,7 +10,6 @@ --background: 240 6% 7%; --foreground: 0 0% 95%; --muted-foreground: 240 4% 60%; - --status-added: 145 45% 55%; } html, body { @@ -26,9 +25,12 @@ cursor: default; } .wrap { text-align: center; } - .face { font-size: 96px; line-height: 1; } + .face { width: 160px; height: 110px; margin: 0 auto; } + .face svg { width: 100%; height: 100%; } + .eye { fill: hsl(var(--foreground)); } + .lid { fill: hsl(var(--background)); } .count { - margin-top: 18px; + margin-top: 10px; font-size: 40px; font-weight: 700; font-variant-numeric: tabular-nums; @@ -43,13 +45,24 @@ .nodes { margin-top: 14px; font-size: 13px; - color: hsl(var(--status-added)); + color: hsl(var(--muted-foreground)); }
-
🙂
+
+ + + + + + + + + +
0
tokens helped compute
 
@@ -74,22 +87,152 @@ window.addEventListener("storage", applyTheme); window.addEventListener("focus", applyTheme); + // ---- Procedural eyes (Cozmo/Vector style) -------------------------- + // Each eye is a rounded rectangle with a bendable bottom edge. Instead + // of canned frames, the rig holds one parameter set and eases it toward + // the current expression every frame, so any state change (and blinks) + // becomes a smooth morph. Inspired by procedural expression polygons: + // https://github.com/ggldnl/Procedural-Expression-Library + // + // Params: w/h size, r corner radius, curve (+ bows the bottom edge up: + // a happy squint), y vertical offset, gaze x drift. + const EXPRESSIONS = { + sleeping: { w: 44, h: 5, r: 2.5, curve: 0, y: 16 }, + waking: { w: 40, h: 22, r: 9, curve: 0, y: 6 }, + neutral: { w: 38, h: 44, r: 12, curve: 0, y: 0 }, + happy: { w: 42, h: 38, r: 13, curve: 16, y: -2 }, + tired: { w: 40, h: 14, r: 6, curve: 0, y: 10 }, + }; + const CENTERS = [46, 114]; // eye x-centers in the 160x110 viewBox + const MID_Y = 48; + + const rig = { + current: { ...EXPRESSIONS.sleeping, gaze: 0 }, + target: { ...EXPRESSIONS.sleeping, gaze: 0 }, + mood: "sleeping", + blink: 1, // height multiplier; dips toward 0 during a blink + blinkPhase: "open", + nextBlinkAt: performance.now() + 2500, + }; + + function eyePath(cx, p, blink) { + const h = Math.max(3, p.h * blink); + const r = Math.min(p.r, h / 2, p.w / 2); + const top = MID_Y + p.y - h / 2; + const bottom = top + h; + const left = cx + p.gaze - p.w / 2; + const right = left + p.w; + return [ + `M ${left + r} ${top}`, + `H ${right - r}`, + `Q ${right} ${top} ${right} ${top + r}`, + `V ${bottom - r}`, + `Q ${right} ${bottom} ${right - r} ${bottom}`, + `H ${left + r}`, + `Q ${left} ${bottom} ${left} ${bottom - r}`, + `V ${top + r}`, + `Q ${left} ${top} ${left + r} ${top}`, + "Z", + ].join(" "); + } + + const eyeL = document.getElementById("eyeL"); + const eyeR = document.getElementById("eyeR"); + const lidL = document.getElementById("lidL"); + const lidR = document.getElementById("lidR"); + + // Lower-lid mask: an ellipse whose top edge rises `curve` px into the + // eye from its bottom, turning the eye into a smooth happy crescent. + function placeLid(lid, cx, p, blink) { + const h = Math.max(3, p.h * blink); + const bottom = MID_Y + p.y + h / 2; + const rise = Math.max(0, p.curve) * blink; + lid.setAttribute("cx", cx + p.gaze); + lid.setAttribute("cy", bottom - rise + 26); + } + + function stepBlink(now) { + if (rig.mood === "sleeping" || rig.mood === "tired") { + rig.blink = 1; + rig.blinkPhase = "open"; + return; + } + if (rig.blinkPhase === "open" && now >= rig.nextBlinkAt) { + rig.blinkPhase = "closing"; + } + if (rig.blinkPhase === "closing") { + rig.blink = Math.max(0.08, rig.blink - 0.28); + if (rig.blink <= 0.08) rig.blinkPhase = "opening"; + } else if (rig.blinkPhase === "opening") { + rig.blink = Math.min(1, rig.blink + 0.22); + if (rig.blink >= 1) { + rig.blinkPhase = "open"; + rig.nextBlinkAt = now + 2200 + Math.random() * 4200; + } + } + } + + let lastGazeShift = 0; + function stepGaze(now) { + if (rig.mood !== "neutral") { + rig.target.gaze = 0; + return; + } + if (now - lastGazeShift > 2800 + Math.random() * 1500) { + lastGazeShift = now; + rig.target.gaze = (Math.random() - 0.5) * 14; + } + } + + function frame(now) { + stepBlink(now); + stepGaze(now); + const c = rig.current; + const t = rig.target; + for (const key of ["w", "h", "r", "curve", "y", "gaze"]) { + c[key] += (t[key] - c[key]) * 0.12; + } + // Sleeping breathes: a slow, gentle bob. + const breath = + rig.mood === "sleeping" ? Math.sin(now / 900) * 1.6 : 0; + const p = { ...c, y: c.y + breath }; + eyeL.setAttribute("d", eyePath(CENTERS[0], p, rig.blink)); + eyeR.setAttribute("d", eyePath(CENTERS[1], p, rig.blink)); + placeLid(lidL, CENTERS[0], p, rig.blink); + placeLid(lidR, CENTERS[1], p, rig.blink); + requestAnimationFrame(frame); + } + requestAnimationFrame(frame); + + function setMood(mood) { + if (rig.mood === mood) return; + rig.mood = mood; + rig.target = { ...EXPRESSIONS[mood], gaze: 0 }; + } + + // ---- State from the mesh runtime ---------------------------------- const invoke = window.__TAURI__?.core?.invoke || window.__TAURI_INTERNALS__?.invoke; async function tick() { if (!invoke) return; try { - const usage = await invoke("mesh_serving_usage"); + const [usage, status] = await Promise.all([ + invoke("mesh_serving_usage"), + invoke("mesh_node_status"), + ]); const tokens = usage?.tokensServed || 0; const inflight = usage?.inflight || 0; document.getElementById("count").textContent = tokens.toLocaleString(); - document.getElementById("face").textContent = - inflight > 0 ? "😄" : tokens > 0 ? "😊" : "🙂"; const nodes = (usage?.peers || 0) + 1; document.getElementById("nodes").textContent = nodes + (nodes === 1 ? " active node in mesh" : " active nodes in mesh"); + const state = status?.state; + if (state === "running") setMood(inflight > 0 ? "happy" : "neutral"); + else if (state === "starting") setMood("waking"); + else if (state === "failed") setMood("tired"); + else setMood("sleeping"); } catch { - // Mesh not running — keep whatever is shown. + setMood("sleeping"); } } tick();