Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion 404.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="页面未找到">
<meta name="theme-color" content="#fffefb">
<meta name="theme-color" content="#c8e4f4">
<meta property="og:title" content="页面未找到 · Musicaldg">
<meta property="og:description" content="页面未找到">
<meta property="og:type" content="website">
Expand Down
42 changes: 42 additions & 0 deletions assets/article.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,31 @@ document.querySelectorAll('.math').forEach(element => {

const headings = Array.from(document.querySelectorAll('.prose h2, .prose h3'));
const links = Array.from(document.querySelectorAll('.toc-links a'));
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
let pending = false;
let flashTimer = 0;

function flashHeading(heading) {
if (!heading || reduceMotion) return;
heading.classList.remove('heading-flash');
void heading.offsetWidth;
heading.classList.add('heading-flash');
window.clearTimeout(flashTimer);
flashTimer = window.setTimeout(() => heading.classList.remove('heading-flash'), 1000);
}

function scrollToHeading(heading, updateHistory) {
if (!heading) return;
heading.scrollIntoView({
behavior: reduceMotion ? 'auto' : 'smooth',
block: 'start'
});
if (updateHistory) {
history.pushState(null, '', '#' + heading.id);
}
flashHeading(heading);
}

function updateDirectory() {
const current = headings.filter(heading => heading.getBoundingClientRect().top <= 140).pop() || headings[0];
links.forEach(link => {
Expand All @@ -26,10 +50,28 @@ function updateDirectory() {
});
pending = false;
}

links.forEach(link => {
link.addEventListener('click', event => {
const heading = document.getElementById(decodeURIComponent(link.hash.slice(1)));
if (!heading) return;
event.preventDefault();
scrollToHeading(heading, true);
});
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TOC jumps skip history scroll

Medium Severity

TOC clicks call preventDefault and history.pushState instead of letting the browser do fragment navigation, and there is no popstate handler. Back and Forward update the hash without moving to that heading, so in-page TOC history no longer restores the previous section.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 70b9ae9. Configure here.


window.addEventListener('scroll', () => {
if (!pending) {
pending = true;
requestAnimationFrame(updateDirectory);
}
}, {passive: true});

if (location.hash) {
const initial = document.getElementById(decodeURIComponent(location.hash.slice(1)));
if (initial) {
window.setTimeout(() => flashHeading(initial), 80);
}
}

updateDirectory();
10 changes: 9 additions & 1 deletion assets/geometry.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
125 changes: 114 additions & 11 deletions assets/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,36 @@
--bg-100: #fffefb;
--bg-200: #f5f4f1;
--bg-300: #cccbc8;
--page-wash: #c8e4f4;
--page-wash-deep: #a9d3eb;
--serif: Georgia, 'Songti SC', 'Noto Serif SC', serif;
--sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif;
}
* { box-sizing: border-box; }
html {
background: var(--page-wash);
scroll-behavior: smooth;
}
body {
margin: 0;
background:
radial-gradient(ellipse 90% 42% at 50% -8%, var(--primary-100), transparent 68%),
var(--bg-100);
min-height: 100svh;
color: var(--text-100);
font: 15px/1.85 var(--sans);
background: transparent;
position: relative;
}
body::before {
content: "";
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
background-color: var(--page-wash);
background-image:
radial-gradient(ellipse 95% 70% at 50% 18%, #9ecfec 0%, transparent 62%),
radial-gradient(ellipse 52% 58% at 0% 48%, color-mix(in srgb, var(--accent-100) 46%, transparent), transparent 72%),
radial-gradient(ellipse 54% 60% at 100% 52%, color-mix(in srgb, #95cceb 75%, var(--accent-100)), transparent 74%),
radial-gradient(ellipse 80% 55% at 50% 100%, var(--page-wash-deep), transparent 68%);
}
a { color: inherit; text-decoration: none; }
a:hover { color: var(--accent-200); }
Expand All @@ -34,16 +53,37 @@ nav a { color: var(--text-200); padding: 6px 12px; border-radius: 999px; }
nav a:hover { color: var(--accent-200); background: color-mix(in srgb, var(--primary-100) 70%, transparent); }
nav a[aria-current=page] { color: var(--accent-200); background: var(--primary-100); }
main { flex: 1; }
.geometry { display: flex; justify-content: center; align-items: center; padding: 8px 0 0; }
.geometry img {
width: min(280px, 78vw);
height: auto;
padding: 18px;
.geometry {
display: flex;
justify-content: center;
align-items: center;
padding: 18px 0 28px;
}
.geometry-glow {
display: grid;
place-items: center;
width: min(250px, 70vw);
aspect-ratio: 1;
border-radius: 50%;
background: radial-gradient(circle, var(--primary-100) 0%, color-mix(in srgb, var(--primary-100) 40%, transparent) 58%, transparent 72%);
background: radial-gradient(circle, color-mix(in srgb, var(--accent-100) 42%, var(--primary-100)) 0%, color-mix(in srgb, var(--primary-100) 45%, transparent) 52%, transparent 72%);
animation: geometry-glow 6s ease-in-out infinite;
}
.geometry-mark {
width: 86%;
height: auto;
display: block;
}
@keyframes geometry-glow {
0%, 100% { transform: scale(1); filter: saturate(1); }
50% { transform: scale(1.035); filter: saturate(1.12); }
}
.lede { margin: 2px 0 40px; text-align: center; color: var(--text-200); font-size: 14px; }
.post-list { display: grid; gap: 18px; padding-bottom: 64px; }
.post-list-compact {
gap: 10px;
max-width: 560px;
margin: 0 auto;
padding-bottom: 56px;
}
.post-list:empty { padding: 0; }
.post-card {
display: block;
Expand All @@ -62,6 +102,43 @@ main { flex: 1; }
box-shadow: 0 16px 36px color-mix(in srgb, var(--accent-200) 12%, transparent);
transform: translateY(-2px);
}
.post-card-compact {
padding: 14px 18px 13px;
border-radius: 12px;
border-top-width: 2px;
box-shadow: 0 6px 18px color-mix(in srgb, var(--primary-300) 4%, transparent);
}
.post-card-compact time {
display: block;
color: var(--text-200);
font-size: 12px;
font-variant-numeric: tabular-nums;
}
.post-card-compact h3 {
font: normal 20px/1.4 var(--serif);
margin: 6px 0 0;
letter-spacing: -.02em;
color: var(--text-100);
}
.post-card-compact .card-summary {
margin: 0;
color: var(--text-200);
font-size: 13px;
line-height: 1.65;
max-height: 0;
opacity: 0;
overflow: hidden;
transform: translateY(-4px);
transition: max-height .28s ease, opacity .22s ease, transform .22s ease, margin .22s ease;
}
.post-card-compact:hover .card-summary,
.post-card-compact:focus-visible .card-summary,
.post-card-compact:focus-within .card-summary {
max-height: 5.5em;
opacity: 1;
margin-top: 8px;
transform: translateY(0);
}
.card-meta { display: flex; gap: 16px; color: var(--text-200); font-size: 12px; font-variant-numeric: tabular-nums; }
.post-card h3 { font: normal 26px/1.45 var(--serif); margin: 12px 0 8px; letter-spacing: -.02em; color: var(--text-100); }
.post-card p { margin: 0; color: var(--text-200); font-size: 14px; line-height: 1.75; }
Expand All @@ -75,7 +152,24 @@ main { flex: 1; }
.article-meta { font-size: 12px; color: var(--text-200); padding-bottom: 25px; margin-bottom: 32px; border-bottom: 1px solid var(--primary-200); }
.text-link { font-size: 13px; color: var(--accent-200); }
.prose { font-size: 16px; line-height: 1.8; overflow-wrap: anywhere; color: var(--text-100); }
.prose h2, .prose h3 { font-family: var(--serif); font-weight: normal; line-height: 1.45; margin-top: 36px; scroll-margin-top: 28px; }
.prose h2, .prose h3 {
font-family: var(--serif);
font-weight: normal;
line-height: 1.45;
margin-top: 36px;
scroll-margin-top: 28px;
border-radius: 8px;
transition: background-color .35s ease;
}
.prose h2.heading-flash,
.prose h3.heading-flash {
animation: heading-flash .95s ease;
}
@keyframes heading-flash {
0% { background-color: color-mix(in srgb, var(--primary-100) 88%, transparent); }
55% { background-color: color-mix(in srgb, var(--accent-100) 22%, transparent); }
100% { background-color: transparent; }
}
.prose a { color: var(--accent-200); text-decoration: underline; text-underline-offset: 3px; }
.prose pre { overflow: auto; background: var(--bg-200); border: 1px solid var(--bg-300); border-radius: 10px; padding: 18px 20px; font-size: 13px; line-height: 1.7; }
.prose code { background: var(--bg-200); border-radius: 4px; padding: 1px 5px; font-size: .9em; }
Expand Down Expand Up @@ -126,6 +220,9 @@ main { flex: 1; }
.lede { letter-spacing: .04em; margin-bottom: 28px; }
.post-card { padding: 22px 20px; }
.post-card h3 { font-size: 22px; }
.post-card-compact { padding: 12px 16px; }
.post-card-compact h3 { font-size: 18px; }
.geometry { padding: 10px 0 20px; }
.article-page .wrap { padding: 0 16px; }
.article-layout { padding-top: 16px; }
.article { padding: 26px 18px 32px; border-radius: 14px; }
Expand All @@ -139,6 +236,12 @@ main { flex: 1; }
.page-intro h1 { font-size: 26px; }
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.post-card { transition: none; }
.post-card:hover { transform: none; }
.post-card-compact .card-summary { transition: none; }
.geometry-glow { animation: none; }
.prose h2, .prose h3 { transition: none; }
.prose h2.heading-flash,
.prose h3.heading-flash { animation: none; }
}
2 changes: 1 addition & 1 deletion blog/active-learning/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="介绍主动学习的基本流程,比较不确定性采样、QBC 和 BALD 三种选样方法。">
<meta name="theme-color" content="#fffefb">
<meta name="theme-color" content="#c8e4f4">
<meta property="og:title" content="Active Learning · Musicaldg">
<meta property="og:description" content="介绍主动学习的基本流程,比较不确定性采样、QBC 和 BALD 三种选样方法。">
<meta property="og:type" content="article">
Expand Down
2 changes: 1 addition & 1 deletion blog/behavior-cloning-plid/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="说明 Behavior Cloning 的状态分布偏移,并推导 PLID / DAgger 如何用交互式专家标签修正策略。">
<meta name="theme-color" content="#fffefb">
<meta name="theme-color" content="#c8e4f4">
<meta property="og:title" content="Behavior Cloning 与 PLID · Musicaldg">
<meta property="og:description" content="说明 Behavior Cloning 的状态分布偏移,并推导 PLID / DAgger 如何用交互式专家标签修正策略。">
<meta property="og:type" content="article">
Expand Down
2 changes: 1 addition & 1 deletion blog/distribution-matching-gail/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="从轨迹与状态—动作分布匹配出发,说明 Forward KL 为何可能退化为 BC,以及 GAIL 如何用判别器完成分布匹配。">
<meta name="theme-color" content="#fffefb">
<meta name="theme-color" content="#c8e4f4">
<meta property="og:title" content="Distribution Matching 与 GAIL · Musicaldg">
<meta property="og:description" content="从轨迹与状态—动作分布匹配出发,说明 Forward KL 为何可能退化为 BC,以及 GAIL 如何用判别器完成分布匹配。">
<meta property="og:type" content="article">
Expand Down
2 changes: 1 addition & 1 deletion blog/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="机器学习笔记。">
<meta name="theme-color" content="#fffefb">
<meta name="theme-color" content="#c8e4f4">
<meta property="og:title" content="文章 · Musicaldg">
<meta property="og:description" content="机器学习笔记。">
<meta property="og:type" content="website">
Expand Down
11 changes: 6 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Musicaldg 的机器学习笔记。">
<meta name="theme-color" content="#fffefb">
<meta name="theme-color" content="#c8e4f4">
<meta property="og:title" content="Musicaldg">
<meta property="og:description" content="Musicaldg 的机器学习笔记。">
<meta property="og:type" content="website">
Expand All @@ -24,11 +24,12 @@
<nav aria-label="主导航"><a href="/blog/" >文章</a><a class="nav-external" href="https://github.com/Musicaldg" aria-label="GitHub 个人主页">GitHub ↗</a></nav>
</header>
<main id="main"><div class="geometry" aria-hidden="true">
<img src="/assets/geometry.svg" alt="" width="320" height="220">
<div class="geometry-glow">
<img class="geometry-mark" src="/assets/geometry.svg" alt="" width="320" height="220">
</div>
</div>
<p class="lede">Musicaldg 的机器学习笔记。</p>
<section class="post-list" aria-label="文章列表">
<a class="post-card" href="/blog/distribution-matching-gail/"><div class="card-meta"><time datetime="2026-11-02">2026-11-02</time><span>约 10 分钟</span></div><h3>Distribution Matching 与 GAIL</h3><p>从轨迹与状态—动作分布匹配出发,说明 Forward KL 为何可能退化为 BC,以及 GAIL 如何用判别器完成分布匹配。</p><span class="card-open">阅读全文 <span aria-hidden="true">↗</span></span></a><a class="post-card" href="/blog/behavior-cloning-plid/"><div class="card-meta"><time datetime="2026-10-20">2026-10-20</time><span>约 10 分钟</span></div><h3>Behavior Cloning 与 PLID</h3><p>说明 Behavior Cloning 的状态分布偏移,并推导 PLID / DAgger 如何用交互式专家标签修正策略。</p><span class="card-open">阅读全文 <span aria-hidden="true">↗</span></span></a><a class="post-card" href="/blog/active-learning/"><div class="card-meta"><time datetime="2026-09-29">2026-09-29</time><span>约 12 分钟</span></div><h3>Active Learning</h3><p>介绍主动学习的基本流程,比较不确定性采样、QBC 和 BALD 三种选样方法。</p><span class="card-open">阅读全文 <span aria-hidden="true">↗</span></span></a>
<section class="post-list post-list-compact" aria-label="文章列表">
<a class="post-card post-card-compact" href="/blog/distribution-matching-gail/" aria-label="Distribution Matching 与 GAIL。从轨迹与状态—动作分布匹配出发,说明 Forward KL 为何可能退化为 BC,以及 GAIL 如何用判别器完成分布匹配。"><time datetime="2026-11-02">2026-11-02</time><h3>Distribution Matching 与 GAIL</h3><p class="card-summary">从轨迹与状态—动作分布匹配出发,说明 Forward KL 为何可能退化为 BC,以及 GAIL 如何用判别器完成分布匹配。</p></a><a class="post-card post-card-compact" href="/blog/behavior-cloning-plid/" aria-label="Behavior Cloning 与 PLID。说明 Behavior Cloning 的状态分布偏移,并推导 PLID / DAgger 如何用交互式专家标签修正策略。"><time datetime="2026-10-20">2026-10-20</time><h3>Behavior Cloning 与 PLID</h3><p class="card-summary">说明 Behavior Cloning 的状态分布偏移,并推导 PLID / DAgger 如何用交互式专家标签修正策略。</p></a><a class="post-card post-card-compact" href="/blog/active-learning/" aria-label="Active Learning。介绍主动学习的基本流程,比较不确定性采样、QBC 和 BALD 三种选样方法。"><time datetime="2026-09-29">2026-09-29</time><h3>Active Learning</h3><p class="card-summary">介绍主动学习的基本流程,比较不确定性采样、QBC 和 BALD 三种选样方法。</p></a>
</section>
</main>
<footer class="footer"><span>© 2026 Musicaldg</span><a href="/feed.xml">RSS</a></footer>
Expand Down
16 changes: 13 additions & 3 deletions scripts/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,22 @@ def page(path, title, description, body, current='', og_type='website'):
url_path = '/' if path == 'index.html' else '/' + path.removesuffix('index.html')
write(path, layout.substitute(name=esc(config['name']), github=esc(config['github']), year=dt.date.today().year, title=esc(title), description=esc(description), canonical=esc(config['url'] + url_path), body=body, home_current='aria-current="page"' if current == 'home' else '', blog_current='aria-current="page"' if current == 'blog' else '', og_type=og_type, page_class='article-page' if og_type == 'article' else '', article_assets='<link rel="stylesheet" href="/assets/vendor/katex/katex.min.css"><script defer src="/assets/vendor/katex/katex.min.js"></script><script defer src="/assets/article.js"></script>' if og_type == 'article' else ''))

def rows(selected):
def blog_rows(selected):
return ''.join(f'<a class="post-card" href="/blog/{p["slug"]}/"><div class="card-meta"><time datetime="{p["date"]}">{p["date"]}</time><span>约 {p["minutes"]} 分钟</span></div><h3>{esc(p["title"])}</h3><p>{esc(p["summary"])}</p><span class="card-open">阅读全文 <span aria-hidden="true">↗</span></span></a>' for p in selected) or EMPTY

home = Template((ROOT / 'templates/home.html').read_text(encoding='utf-8')).substitute(name=esc(config['name']), github=esc(config['github']), description=esc(config['description']), posts=rows(posts[:5]))
def home_rows(selected):
return ''.join(
f'<a class="post-card post-card-compact" href="/blog/{p["slug"]}/" aria-label="{esc(p["title"])}。{esc(p["summary"])}">'
f'<time datetime="{p["date"]}">{p["date"]}</time>'
f'<h3>{esc(p["title"])}</h3>'
f'<p class="card-summary">{esc(p["summary"])}</p>'
f'</a>'
for p in selected
) or EMPTY

home = Template((ROOT / 'templates/home.html').read_text(encoding='utf-8')).substitute(posts=home_rows(posts[:5]))
page('index.html', config['name'], config['description'], home, 'home')
page('blog/index.html', '文章 · ' + config['name'], '机器学习笔记。', '<div class="page-intro"><h1>文章</h1></div><section class="post-list">' + rows(posts) + '</section>', 'blog')
page('blog/index.html', '文章 · ' + config['name'], '机器学习笔记。', '<div class="page-intro"><h1>文章</h1></div><section class="post-list">' + blog_rows(posts) + '</section>', 'blog')
page('404.html', '页面未找到 · ' + config['name'], '页面未找到', '<div class="not-found"><h1>404</h1><p>页面未找到</p><a class="text-link" href="/">回到首页 ↗</a></div>')
for post in posts:
toc = '<nav class="toc-links" aria-label="文章目录">' + post['toc'] + '</nav>'
Expand Down
7 changes: 4 additions & 3 deletions templates/home.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<div class="geometry" aria-hidden="true">
<img src="/assets/geometry.svg" alt="" width="320" height="220">
<div class="geometry-glow">
<img class="geometry-mark" src="/assets/geometry.svg" alt="" width="320" height="220">
</div>
</div>
<p class="lede">$description</p>
<section class="post-list" aria-label="文章列表">
<section class="post-list post-list-compact" aria-label="文章列表">
$posts
</section>
2 changes: 1 addition & 1 deletion templates/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="$description">
<meta name="theme-color" content="#fffefb">
<meta name="theme-color" content="#c8e4f4">
<meta property="og:title" content="$title">
<meta property="og:description" content="$description">
<meta property="og:type" content="$og_type">
Expand Down
Loading