diff --git a/static/css/iris-demo.css b/static/css/iris-demo.css index bac94fa077..96e555ea8d 100644 --- a/static/css/iris-demo.css +++ b/static/css/iris-demo.css @@ -18,11 +18,10 @@ .iris:not(.iris-preview) .iris-stagewrap { max-width: 75%; margin-left: auto; margin-right: auto; } @media (max-width: 640px) { .iris:not(.iris-preview) .iris-stagewrap { max-width: 100%; } } .iris-stage { position: relative; aspect-ratio: 613.5 / 423.5; /* VIEW in iris-demo.js */ border-radius: 11px; overflow: hidden; background: #0D212C; } -/* The four published versions of the drawing, stacked twice. In a stack, a step shows the versions it needs and the - script sets how they blend; isolation keeps that blend inside the stack. The new stack fades in over the old one. */ +/* The published versions of the drawing, in two stacks. In a stack, a step shows the versions it needs as background + images, and the script sets how they blend. The new stack fades in over the old one. */ .iris-artset { position: absolute; inset: 0; isolation: isolate; opacity: 0; transition: opacity .45s; } -.iris .iris-art { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; margin: 0; opacity: 0; pointer-events: none; user-select: none; } -.iris .iris-art.is-on { opacity: 1; } +.iris .iris-art { position: absolute; margin: 0; background-size: 100% 100%; background-repeat: no-repeat; pointer-events: none; user-select: none; } .iris-over { position: absolute; inset: 0; width: 100%; height: 100%; display: block; } .iris-route { fill: none; stroke: none; } .iris-hit { fill: transparent; cursor: pointer; } diff --git a/static/js/iris-demo.js b/static/js/iris-demo.js index 3466b044c2..1d5bb7936d 100644 --- a/static/js/iris-demo.js +++ b/static/js/iris-demo.js @@ -564,18 +564,26 @@ Each version of the drawing shows its lit service's label box, and data-integration.svg also shows the Context Retriever box. The stage draws the same box, with the current name, at the same place, and shows it whenever a version in `in` is lit (see compose()). Boxes are x, y, width, height, copied from - langcache.svg and context-retriever.svg. */ + langcache.svg and context-retriever.svg. + The Redis and agent labels are lit in every version, so the stage draws them as text too, always shown + (`always`), with their boxes copied from agent-memory.svg. They then look exactly like the labels the stage + adds, such as Maya's. The agent's box is as tall as Maya's, so its text sits as Maya's does (`base`). */ var RELABEL = { cache: { box: [471.578, 518.156, 99.2506, 24.4832], lines: ["AGENT PLAYBOOKS"], in: ["cache"] }, - retriever: { box: [498.461, 235.889, 99.2506, 31.2039], lines: ["CONTEXT", "GATEWAY"], in: ["retriever"] } + retriever: { box: [498.461, 235.889, 99.2506, 31.2039], lines: ["CONTEXT", "GATEWAY"], in: ["retriever"] }, + redis: { box: [370.684, 287.974, 84.6654, 32.7885], lines: ["REDIS SEARCH", "(IN REDIS DB)"], always: true }, + agent: { box: [632.932, 436.729, 43.1543, 24.751], lines: ["AGENT"], always: true, rx: 3.78037, stroke: 0.840082, base: 3.69 } }; function buildRelabels(NS) { var out = {}; Object.keys(RELABEL).forEach(function (k) { var R = RELABEL[k], b = R.box, g = document.createElementNS(NS, "g"); - var mid = b[1] + b[3] / 2, gap = 10, first = mid - (R.lines.length - 1) * gap / 2 + 2.95; // 2.95: half the glyphs' cap height - g.setAttribute("class", "iris-relabel"); - g.innerHTML = '' + + var mid = b[1] + b[3] / 2, gap = 10, first = mid - (R.lines.length - 1) * gap / 2 + (R.base || 2.95); // 2.95: half the glyphs' cap height + g.setAttribute("class", "iris-relabel" + (R.always ? " is-on" : "")); + /* An always-shown box first covers the drawing's own box, 2 units larger all round: the drawing can land up to + a device pixel away from the overlay, so its outline would otherwise show at the edges. */ + g.innerHTML = (R.always ? '' : "") + + '' + R.lines.map(function (t, i) { return '' + esc(t) + ""; }).join(""); @@ -674,22 +682,19 @@ var box = el("div", "iris-stage"); box.setAttribute("role", "img"); /* Two stacks of the versions. A step blends its versions in the stack that isn't showing, then - fades that stack in over the other, so a half-faded version never blends the wrong way. */ + fades that stack in over the other, so a half-faded version never blends the wrong way. + Each stack is one element with the versions as its background images, blended with + background-blend-mode. Stacked images blended with mix-blend-mode would do the same, but Chrome + draws them at a lower resolution, and "darken" then thins the labels' text. */ var sets = [0, 1].map(function () { - var set = el("div", "iris-artset"), layers = {}; - ["retriever", "cache", "memory"].forEach(function (k) { - var img = el("img", "iris-art"); - img.style.left = vx(0); img.style.top = vy(0); img.style.width = vw(ART_W); img.style.height = vh(ART_H); - img.src = artBase + ART[k]; - img.alt = ""; - img.decoding = "async"; - img.draggable = false; - set.appendChild(img); - layers[k] = img; - }); + var set = el("div", "iris-artset"), art = el("div", "iris-art"); + art.style.left = vx(0); art.style.top = vy(0); art.style.width = vw(ART_W); art.style.height = vh(ART_H); + set.appendChild(art); box.appendChild(set); - return { el: set, layers: layers }; + return { el: set, art: art }; }); + /* Load every version up front, so the first step that uses one doesn't wait for it. */ + var preload = ["retriever", "cache", "memory"].map(function (k) { var i = new Image(); i.src = artBase + ART[k]; return i; }); var cur = sets[1]; var NS = "http://www.w3.org/2000/svg"; var over = document.createElementNS(NS, "svg"); @@ -750,13 +755,11 @@ /* Show some versions of the drawing: the first one as is, the rest blended onto it. */ function compose(keys, blend) { - var first = true, next = cur === sets[0] ? sets[1] : sets[0]; - ["retriever", "cache", "memory"].forEach(function (k) { - var on = keys.indexOf(k) >= 0, img = next.layers[k]; - img.classList.toggle("is-on", on); - img.style.mixBlendMode = on && !first ? (blend || "lighten") : "normal"; - if (on) first = false; - }); + var next = cur === sets[0] ? sets[1] : sets[0]; + var shown = ["retriever", "cache", "memory"].filter(function (k) { return keys.indexOf(k) >= 0; }); + next.art.style.backgroundImage = shown.map(function (k) { return 'url("' + artBase + ART[k] + '")'; }).join(", "); + next.art.style.backgroundBlendMode = shown.length > 1 ? (blend || "lighten") : "normal"; + next.art.dataset.versions = shown.join(" "); // what the stack shows, for the tests /* The showing stack stays put underneath; the new one starts clear on top and fades in. */ cur.el.style.transition = "none"; cur.el.style.opacity = "1"; @@ -771,8 +774,10 @@ cur = next; /* Agent Playbooks' disc is lit where its version is, as its label is. */ pbDisc.classList.toggle("is-lit", keys.indexOf("cache") >= 0 && (keys.length === 1 || blend !== "darken")); - /* A label shows where a version that has it is lit; "darken" keeps only what every version lights, which no label is. */ + /* A label shows where a version that has it is lit; "darken" keeps only what every version lights, which no service's + label is. The Redis and agent labels always show. */ Object.keys(relabels).forEach(function (k) { + if (RELABEL[k].always) return; var shown = RELABEL[k].in.some(function (v) { return keys.indexOf(v) >= 0; }); relabels[k].classList.toggle("is-on", shown && (keys.length === 1 || blend !== "darken")); });