Skip to content

Commit 260fe7c

Browse files
authored
Merge pull request #4 from wanshuiyin/fix/p0-skill-drift-and-review-guard
P0 SKILL-drift fix + review-chain guard + dllm Focus-dim reflow (B1/B2/B4)
2 parents b2ebc8d + 00dc76e commit 260fe7c

52 files changed

Lines changed: 8733 additions & 164 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/tutorials/3d_generation_tutorial.html

Lines changed: 169 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<meta name="generator" content="ARIS render-html (academic, v1)">
99
<meta name="aris:source-path" content="docs/tutorials/3d_generation_tutorial.md">
1010
<meta name="aris:source-sha256" content="beab28036da8f28744b8d64815a669d0fce44c978bd869145e41b15860659ccc">
11-
<meta name="aris:generated-at" content="2026-05-27 15:19 UTC">
11+
<meta name="aris:generated-at" content="2026-05-31 05:07 UTC">
1212

1313
<!-- MathJax 3 -->
1414
<script>
@@ -462,6 +462,56 @@
462462
padding-left: 12px;
463463
margin-left: -12px;
464464
}
465+
466+
/* --- Focus-dim reading mode (B1) + floating toggle (B2) + ↑/↓ nav (B4) -----
467+
Blog opt-in. Everything is scoped under body.aris-blog(.aris-focus-dim) so
468+
the 46 non-blog tutorials are completely unaffected (no .aris-blog → button
469+
hidden, dim rule never matches). While ON, dims every <main> child except
470+
the current section and the intro (header.hero stays bright). F7's io2 is
471+
paused while ON; the scroll listener is bound only while ON. */
472+
body.aris-blog.aris-focus-dim main > *:not(.aris-in-focus) {
473+
opacity: 0.28;
474+
transition: opacity 0.25s ease;
475+
}
476+
body.aris-blog.aris-focus-dim main > .aris-in-focus { opacity: 1; }
477+
.aris-focus-toggle {
478+
position: fixed;
479+
top: 16px;
480+
right: 16px;
481+
z-index: 1100;
482+
display: none;
483+
background: var(--bg);
484+
border: 1px solid var(--border);
485+
border-radius: 18px;
486+
padding: 6px 13px;
487+
font-family: inherit;
488+
font-size: 13px;
489+
color: var(--ink-muted);
490+
cursor: pointer;
491+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
492+
}
493+
body.aris-blog .aris-focus-toggle { display: inline-block; }
494+
.aris-focus-toggle:hover { color: var(--primary); }
495+
.aris-focus-toggle.on { background: var(--accent); color: #fff; border-color: var(--accent); }
496+
.aris-focus-hint {
497+
position: fixed;
498+
bottom: 18px;
499+
right: 16px;
500+
z-index: 1100;
501+
background: rgba(0, 0, 0, 0.78);
502+
color: #fff;
503+
font-size: 12px;
504+
padding: 6px 12px;
505+
border-radius: 6px;
506+
opacity: 0;
507+
transition: opacity 0.3s ease;
508+
pointer-events: none;
509+
}
510+
.aris-focus-hint.show { opacity: 1; }
511+
@media print {
512+
.aris-focus-toggle, .aris-focus-hint { display: none !important; }
513+
body.aris-focus-dim main > * { opacity: 1 !important; }
514+
}
465515
</style>
466516
</head>
467517
<body class="">
@@ -580,7 +630,7 @@ <h1>3D Generation 面试 Cheat Sheet</h1>
580630
<div class="meta">
581631
<span><strong>Source:</strong> <code>docs/tutorials/3d_generation_tutorial.md</code></span>
582632
<span><strong>SHA256:</strong> <code>beab28036da8</code></span>
583-
<span><strong>Rendered:</strong> 2026-05-27 15:19 UTC</span>
633+
<span><strong>Rendered:</strong> 2026-05-31 05:07 UTC</span>
584634

585635
</div>
586636
</header>
@@ -1155,7 +1205,7 @@ <h3 id="a3-embodied-ai--ar--vr-常见追问">A.3 Embodied AI / AR / VR 常见
11551205
Generated by <a href="https://github.com/wanshuiyin/Auto-claude-code-research-in-sleep/blob/main/skills/render-html/SKILL.md">ARIS <code>/render-html</code></a> ·
11561206
source path <code>docs/tutorials/3d_generation_tutorial.md</code> ·
11571207
SHA256 <code>beab28036da8</code> ·
1158-
generated at 2026-05-27 15:19 UTC.
1208+
generated at 2026-05-31 05:07 UTC.
11591209
This is a generated view — edit the source Markdown, then re-render.
11601210
</footer>
11611211
</main>
@@ -1366,6 +1416,122 @@ <h3 id="a3-embodied-ai--ar--vr-常见追问">A.3 Embodied AI / AR / VR 常见
13661416
}, { rootMargin: "-15% 0px -75% 0px" });
13671417
h2s.forEach(function (h) { io2.observe(h); });
13681418
}
1419+
1420+
// --- Feature 8: Focus-dim reading mode (B1) + floating toggle (B2) +
1421+
// ↑/↓ section nav (B4). Built only inside this .aris-blog guard, so
1422+
// non-blog tutorials never construct it. Default OFF. While ON:
1423+
// dims non-current sections (h3-granular), keeps the intro bright,
1424+
// pauses F7's io2, and binds a scroll listener (removed on OFF — no
1425+
// new *persistent* global hook). Restores everything on OFF / print.
1426+
var mainEl = document.querySelector("main");
1427+
if (mainEl) {
1428+
var focusBtn = document.createElement("button");
1429+
focusBtn.className = "aris-focus-toggle";
1430+
focusBtn.type = "button";
1431+
focusBtn.setAttribute("aria-pressed", "false");
1432+
focusBtn.textContent = "🎯 Focus";
1433+
document.body.appendChild(focusBtn);
1434+
1435+
var focusHint = document.createElement("div");
1436+
focusHint.className = "aris-focus-hint";
1437+
document.body.appendChild(focusHint);
1438+
var hintTimer = null;
1439+
var showFocusHint = function (msg) {
1440+
focusHint.textContent = msg;
1441+
focusHint.classList.add("show");
1442+
if (hintTimer) clearTimeout(hintTimer);
1443+
hintTimer = setTimeout(function () { focusHint.classList.remove("show"); }, 1600);
1444+
};
1445+
1446+
var focusKids = function () { return [].slice.call(mainEl.children); };
1447+
var headerIdxList = function (kids) {
1448+
var idxs = [];
1449+
kids.forEach(function (el, i) {
1450+
if (el.tagName === "H2" || el.tagName === "H3") idxs.push(i);
1451+
});
1452+
return idxs;
1453+
};
1454+
// Deterministic current-section pick (no IntersectionObserver): the
1455+
// header whose top is closest to but above the viewport's 40% line;
1456+
// fallback = first header still below the line; then first header.
1457+
var activeHeaderIdx = function (kids, headerIdxs) {
1458+
var best = -1, bestTop = -Infinity, lineY = window.innerHeight * 0.4;
1459+
headerIdxs.forEach(function (idx) {
1460+
var top = kids[idx].getBoundingClientRect().top;
1461+
if (top < lineY && top > bestTop) { bestTop = top; best = idx; }
1462+
});
1463+
if (best < 0) {
1464+
for (var i = 0; i < headerIdxs.length; i++) {
1465+
if (kids[headerIdxs[i]].getBoundingClientRect().top >= 0) { best = headerIdxs[i]; break; }
1466+
}
1467+
if (best < 0) best = headerIdxs[0];
1468+
}
1469+
return best;
1470+
};
1471+
var updateFocus = function () {
1472+
var kids = focusKids();
1473+
var headerIdxs = headerIdxList(kids);
1474+
if (!headerIdxs.length) { // no h2/h3 → keep all bright (never dim a headerless page)
1475+
kids.forEach(function (el) { el.classList.add("aris-in-focus"); });
1476+
return;
1477+
}
1478+
var best = activeHeaderIdx(kids, headerIdxs);
1479+
var next = kids.length;
1480+
for (var j = 0; j < headerIdxs.length; j++) {
1481+
if (headerIdxs[j] > best) { next = headerIdxs[j]; break; }
1482+
}
1483+
var introEnd = headerIdxs[0]; // header.hero + anything before first heading stays bright
1484+
kids.forEach(function (el, i) {
1485+
el.classList.toggle("aris-in-focus", (i < introEnd) || (i >= best && i < next));
1486+
});
1487+
};
1488+
var onFocusScroll = function () {
1489+
if (document.body.classList.contains("aris-focus-dim")) updateFocus();
1490+
};
1491+
var onFocusKeydown = function (e) {
1492+
var tg = e.target;
1493+
if (tg && (tg.tagName === "INPUT" || tg.tagName === "TEXTAREA" || tg.tagName === "SELECT" || tg.isContentEditable)) return;
1494+
if (e.key === "Escape") {
1495+
var popEl = document.getElementById("cite-pop");
1496+
if (popEl && !popEl.hidden) return; // an open popover handles Esc first
1497+
setFocus(false);
1498+
return;
1499+
}
1500+
if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return;
1501+
e.preventDefault();
1502+
var heads = [].slice.call(document.querySelectorAll("main h2, main h3"));
1503+
if (!heads.length) return;
1504+
var cur = 0, bestDist = Infinity;
1505+
heads.forEach(function (h, i) {
1506+
var d = Math.abs(h.getBoundingClientRect().top - 80);
1507+
if (d < bestDist) { bestDist = d; cur = i; }
1508+
});
1509+
var ni = e.key === "ArrowDown" ? Math.min(cur + 1, heads.length - 1) : Math.max(cur - 1, 0);
1510+
heads[ni].scrollIntoView({ behavior: "smooth", block: "start" });
1511+
showFocusHint((ni + 1) + " / " + heads.length + " " + heads[ni].textContent.trim().slice(0, 24));
1512+
};
1513+
var setFocus = function (on) {
1514+
document.body.classList.toggle("aris-focus-dim", on);
1515+
focusBtn.classList.toggle("on", on);
1516+
focusBtn.setAttribute("aria-pressed", on ? "true" : "false");
1517+
focusBtn.textContent = on ? "🎯 Focus ON" : "🎯 Focus";
1518+
if (on) {
1519+
window.addEventListener("scroll", onFocusScroll, { passive: true });
1520+
document.addEventListener("keydown", onFocusKeydown, true); // capture phase: see an open popover before its bubble Esc handler (also: bound only while ON, guardrail 2)
1521+
if (typeof io2 !== "undefined" && io2) io2.disconnect(); // pause F7
1522+
updateFocus();
1523+
showFocusHint("Focus 模式:↑ / ↓ 切换小节,Esc 退出");
1524+
} else {
1525+
window.removeEventListener("scroll", onFocusScroll);
1526+
document.removeEventListener("keydown", onFocusKeydown, true);
1527+
focusKids().forEach(function (el) { el.classList.remove("aris-in-focus"); });
1528+
if (typeof io2 !== "undefined" && io2) h2s.forEach(function (h) { io2.observe(h); }); // resume F7
1529+
}
1530+
};
1531+
focusBtn.addEventListener("click", function () {
1532+
setFocus(!document.body.classList.contains("aris-focus-dim"));
1533+
});
1534+
}
13691535
}
13701536
})();
13711537
</script>

0 commit comments

Comments
 (0)