v0.3.0-alpha: Chromium rasterizer (R4), branching, chapters
- Rasterizer: playwright-core + system Chromium renders dom steps to PNG (1280x800, JavaScript disabled — snapshots stay inert). Cached permanently on the step (dom_html immutable). CHROMIUM_PATH configurable. - Video render now includes DOM steps as real frames (verified h264 1280x800, 0 skipped); guides now show rasterized screenshots for DOM steps - Branching: per-step branch hotspots (dashed, labeled) jumping to any target step; lead gates respected on branch jumps - Chapters: demo-level chapter menu in player bar - API: PATCH /api/demos/:id (name, chapters), branches on step patch, both in public JSON - MCP surface: 15 tools (+set_step_branches, +set_chapters) - Docker: chromium + fonts in runtime image, CHROMIUM_PATH preset
This commit is contained in:
parent
a535e15253
commit
928628f49a
11 changed files with 269 additions and 27 deletions
|
|
@ -41,6 +41,17 @@
|
|||
}
|
||||
snap.appendChild(container);
|
||||
|
||||
(step.branches || []).forEach(function (br) {
|
||||
var bh = document.createElement("div");
|
||||
bh.className = "hotspot";
|
||||
bh.style.left = br.x + "%"; bh.style.top = br.y + "%";
|
||||
bh.style.width = br.w + "%"; bh.style.height = br.h + "%";
|
||||
bh.style.borderStyle = "dashed";
|
||||
if (br.label) bh.title = br.label;
|
||||
bh.addEventListener("click", function () { jumpTo(br.target_step_id); });
|
||||
snap.appendChild(bh);
|
||||
});
|
||||
|
||||
if (step.hotspot) {
|
||||
var h = document.createElement("div");
|
||||
h.className = "hotspot";
|
||||
|
|
@ -112,6 +123,19 @@
|
|||
snap.appendChild(overlay);
|
||||
}
|
||||
|
||||
function jumpTo(stepId) {
|
||||
var idx = state.demo.steps.findIndex(function (s) { return s.id === stepId; });
|
||||
if (idx < 0) return;
|
||||
var cur = state.demo.steps[state.i];
|
||||
if (cur.lead_gate && cur.lead_gate.enabled && !gatePassed[cur.id]) {
|
||||
showGate(cur, function () { jumpTo(stepId); });
|
||||
return;
|
||||
}
|
||||
state.i = idx;
|
||||
beacon("advance", stepId);
|
||||
render();
|
||||
}
|
||||
|
||||
function next() {
|
||||
var cur = state.demo.steps[state.i];
|
||||
if (cur.lead_gate && cur.lead_gate.enabled && !gatePassed[cur.id]) {
|
||||
|
|
@ -145,6 +169,18 @@
|
|||
.then(function (demo) {
|
||||
state.demo = demo;
|
||||
titleEl.textContent = demo.name;
|
||||
if (demo.chapters && demo.chapters.length) {
|
||||
var sel = document.createElement("select");
|
||||
sel.style.cssText = "border:1px solid #e2e8f0;border-radius:6px;padding:5px 8px;font:inherit;max-width:180px";
|
||||
var opt0 = document.createElement("option");
|
||||
opt0.textContent = "Chapters"; opt0.value = ""; sel.appendChild(opt0);
|
||||
demo.chapters.forEach(function (c) {
|
||||
var o = document.createElement("option");
|
||||
o.value = c.step_id; o.textContent = c.title; sel.appendChild(o);
|
||||
});
|
||||
sel.addEventListener("change", function () { if (sel.value) { jumpTo(sel.value); sel.value = ""; } });
|
||||
titleEl.parentNode.insertBefore(sel, titleEl.nextSibling);
|
||||
}
|
||||
document.title = demo.name;
|
||||
beacon("view", demo.steps.length ? demo.steps[0].id : null);
|
||||
render();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue