Spaces:
Running
Running
File size: 4,733 Bytes
2ce6518 d32737a 2ce6518 d32737a 2ce6518 d32737a 2ce6518 d32737a 2ce6518 d32737a 2ce6518 d32737a 2ce6518 d32737a 2ce6518 d32737a 2ce6518 d32737a 2ce6518 d32737a 2ce6518 9b672a8 2ce6518 cbd6f7b d32737a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | /* Narrative / structural beat card — the fallback that carries the paper's STORY beats (problem, prior
* work, method framing, takeaway) and structural concepts (flow / cycle / timeline / layers / tree /
* compare). It animates the beat's own points into a tasteful, staggered diagram: bullet flow, a
* two-column "existing approaches vs this work" for compare, a vertical stack for layers/tree. Each beat
* gets a kind pill so the whole paper reads as problem → prior → method → results → takeaway. */
(function () {
const k = MANIMO.kit;
const KIND = {
problem: "Problem", pain: "Why it hurts", prior: "Prior work", compare: "Existing vs this",
title: "The big question", hook: "The big question", takeaway: "Takeaway", closing: "Takeaway",
results: "Result", flow: "Pipeline", cycle: "Cycle", timeline: "Timeline", layers: "Layers", tree: "Tree",
};
function labelsOf(p) {
return p.stages || p.layers || p.points || p.nodes || p.children || p.terms || [];
}
function mount(root, concept, theme) {
const p = (concept && concept.params) || {};
const prim = (concept && concept.primitive) || "concept";
const kindLabel = KIND[prim] || (concept && concept.beat && KIND[concept.beat]) || "Concept";
const isCompare = prim === "compare" && (p.left || p.right);
const isVertical = (prim === "layers" || prim === "tree");
let labels = labelsOf(p).slice(0, 8).map(String);
if (!labels.length && !isCompare) labels = (concept.label ? [concept.label] : ["this concept"]);
const head = k.el("div", { class: "beat-head" }, [
k.el("span", { class: "beat-kind" }, [kindLabel]),
k.el("span", { class: "beat-ttl" }, [concept.title || concept.label || ""]),
]);
const stage = k.el("div", { class: "diagram " + prim + (isVertical ? " vert" : "") });
function chip(text, i) {
const c = k.el("div", { class: "node", style: "animation-delay:" + (i * 90) + "ms" }, [String(text)]);
if (prim === "cycle" || prim === "flow") c.classList.add("flowy");
return c;
}
function arrow(kind) { return k.el("div", { class: "arrow" }, [kind === "cycle" ? "↻" : "→"]); }
function drawCompare() {
k.clear(stage); stage.classList.add("compare");
const cols = [["Existing approaches", p.left || [], "old"], ["This work", p.right || [], "new"]];
cols.forEach(([ttl, items, cls], ci) => {
const col = k.el("div", { class: "vs-col " + cls });
col.appendChild(k.el("div", { class: "vs-h" }, [ttl]));
(items || []).slice(0, 6).forEach((it, i) => col.appendChild(k.el("div", { class: "node", style: "animation-delay:" + ((ci * 3 + i) * 110) + "ms" }, [String(it)])));
stage.appendChild(col);
if (ci === 0) stage.appendChild(k.el("div", { class: "vs-mid" }, ["vs"]));
});
}
function draw() {
if (isCompare) return drawCompare();
k.clear(stage);
if (prim === "tree" && labels.length) {
stage.appendChild(k.el("div", { class: "node root", style: "animation-delay:0ms" }, [labels[0]]));
const kids = k.el("div", { class: "kids" });
labels.slice(1).forEach((l, i) => kids.appendChild(chip(l, i + 1)));
stage.appendChild(kids);
return;
}
labels.forEach((l, i) => {
stage.appendChild(chip(l, i));
if (!isVertical && i < labels.length - 1) stage.appendChild(arrow(prim));
});
if (prim === "cycle" && labels.length) stage.appendChild(arrow("cycle"));
}
const editor = !isCompare ? k.el("input", { class: "lbledit", value: labels.join(", "), title: "edit labels (comma-separated)" }) : null;
if (editor) editor.addEventListener("input", () => { labels = editor.value.split(",").map((s) => s.trim()).filter(Boolean).slice(0, 8); draw(); });
root.appendChild(head);
if (concept.explainer) root.appendChild(k.el("p", { class: "explainer" }, [concept.explainer]));
const ctrls = [k.chip(prim, true)];
if (editor) ctrls.push(k.el("label", { class: "fld" }, ["labels ", editor]));
root.appendChild(k.row(ctrls, "ctrls"));
root.appendChild(stage);
root.appendChild(k.row([k.button("↻ Replay", draw, "ghost")], "ctrls"));
draw();
// player: re-run the staggered reveal, then signal done once the last node has popped in.
let to = null;
function stop() { if (to) { clearTimeout(to); to = null; } }
const beats = isCompare ? ((p.left || []).length + (p.right || []).length) : labels.length;
return { play: (done) => { stop(); draw(); to = setTimeout(() => { to = null; if (done) done(); }, Math.max(1500, beats * 190 + 950)); }, stop, reset: draw };
}
MANIMO.registry["_generic"] = { title: "Concept", mount };
})();
|