/* — where the fly is heading right now. * * The flight reports a `target` event on every step (throttled server-side to a * sane rate), naming the word it currently pulls toward. That word changes * fast — several per second — and this element shows it as a running line, with * a short trail of the words it passed on the way. This is the fly *flying*, * not the fly eating: the meal stream (workshop-words) stays separate and still * arrives ~once every ten seconds. * * A `target` with `none: true` means every word was on cooldown — there is no * destination at that moment, and the element says so instead of freezing on a * stale word. * * Honesty: the fly does not "want" or "aim" — "target" is our layer over the * brain's state. Which word wins is measured (`sim`); the hungriness shown is * the author's frame, labelled on the page. */ class WorkshopTarget extends HTMLElement { connectedCallback() { this.trailLen = parseInt(this.getAttribute("trail") || "8", 10); this.trail = []; this.current = null; this.render(); this._off = WorkshopStream.on("target", (ev) => this.push(ev)); } disconnectedCallback() { if (this._off) this._off(); } push(ev) { this.current = ev; if (!ev.none && ev.term && ev.term !== (this.trail[0] && this.trail[0].term)) { this.trail.unshift(ev); if (this.trail.length > this.trailLen) this.trail.pop(); } this.render(); } render() { const cur = this.current; let head; if (!cur) { head = 'полёт ещё не пошёл — муха ждёт настроения от мозга'; } else if (cur.none) { head = 'нет цели · все слова отрастают'; } else { const sim = typeof cur.sim === "number" ? cur.sim.toFixed(3) : "—"; const hunger = typeof cur.hunger === "number" ? cur.hunger.toFixed(2) : "—"; const entropy = typeof cur.entropy === "number" ? cur.entropy.toFixed(2) : "—"; const tip = `lang=${cur.lang} sim=${sim} step=${cur.step} ` + `hunger=${hunger} entropy=${entropy}`; head = `` + `${escapeHtml(cur.term)}${sim}`; } const trail = this.trail.slice(1).map((t) => `${escapeHtml(t.term)}` ).join(""); this.innerHTML = `
цель сейчас:` + `${head}
` + (trail ? `
${trail}
` : ""); } } function escapeHtml(s) { return String(s).replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'", })[c]); } customElements.define("workshop-target", WorkshopTarget);