Skip to content

Commit 61003d6

Browse files
RuitingMaclaude
andcommitted
Essays: scaffold five score-themed drafts; demote test page
Five new drafts seeded with cue-sectioned skeletons + TODO outlines, each embedding the relevant Score instance(s). All marked draft so they only render in dev: - shui-zhi-xi-xi — Ravel's Jeux d'eau, personal angle (NOTE, mist) - pei-pu — scrolling score as reading companion (NOTE, plum) - gun-pu-de-zha-fa — engineering tour, MEI → renderer (ESSAY, dune) - dong-jie-de-bao-tou — frozen header / chrome overlay deep dive (ESSAY, rust) - xi-tong-pai-zhun — audio scheduling + visual sync (ESSAY, moss) Demote jeux-deau-test.mdx to draft and rename it "Score 组件测试页" so it stays as a permanent dev-only regression page (5 score instances in one place, including the chaos and all-keys stress tests). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent fae470d commit 61003d6

6 files changed

Lines changed: 396 additions & 2 deletions

File tree

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
title: 冻结的报头
3+
date: "2026-05-04"
4+
kind: ESSAY
5+
summary: 谱面在动,谱号、调号、拍号永远在最左边——这块小区域比看上去复杂。
6+
tint: rust
7+
draft: true
8+
---
9+
10+
import Score from '../../components/Score.astro';
11+
12+
{/*
13+
起草大纲(按 cue 顺序):
14+
15+
problem — 横向滚动的谱面,最左边那块"报头"是阅读的语境锚。
16+
离开它你不知道现在是什么调、什么拍。
17+
但谱面在动,报头如果跟着动就废了;如果不动就要
18+
单独造一个不动的副本。
19+
per-axis — 这个副本不能是一整块。clef / keysig / meter 三
20+
个轴各有自己的变化节奏。chrome overlay 设计成
21+
三个独立的 track,每个 track 一个 stack of layers,
22+
按播放头位置二分查找。
23+
per-staff — 还要按 staff 分。钢琴大谱表上层换谱号,下层不
24+
该跟着闪。每个 (staff × axis) 是一个独立 track。
25+
signature — 怎么 dedup?不靠 MEI 元数据——靠"渲染出来的
26+
`<use xlink:href>` 列表"。两个 layer 视觉一致就
27+
合并。 cancel-natural (E261) 在 signature 里被
28+
剥掉。
29+
small-vs-full — 今天补的一刀:mid-piece courtesy 谱号 (E07A)
30+
被克隆到报头时还是小变体——明显小一圈。映射到
31+
full (E050) 后视觉一致。
32+
keysig-width — 5 个升 → 6 个降的转调,调号宽度从窄变宽。meter
33+
的位置必须跟着滑,但要"提前"留空间,不然窄调号
34+
时 meter 会朝左靠,宽调号时被推开。预扫一遍找
35+
maxKeysigWidth。
36+
recap — 报头是一个"假装不动"的小宇宙。每一处看起来稳
37+
的东西,背后都在做交叉淡入。
38+
*/}
39+
40+
<section data-cue="problem">
41+
42+
{/* TODO: 报头作为阅读语境锚。 */}
43+
44+
<Score slug="jeux-deau" />
45+
46+
</section>
47+
48+
<section data-cue="per-axis">
49+
50+
{/* TODO: 三个轴独立。 */}
51+
52+
</section>
53+
54+
<section data-cue="per-staff">
55+
56+
{/* TODO: 多谱表的独立 track。 */}
57+
58+
</section>
59+
60+
<section data-cue="signature">
61+
62+
{/* TODO: visual signature dedup,不依赖 MEI。 */}
63+
64+
</section>
65+
66+
<section data-cue="small-vs-full">
67+
68+
{/* TODO: SMuFL E07A → E050 的映射。 */}
69+
70+
</section>
71+
72+
<section data-cue="keysig-width">
73+
74+
{/* TODO: maxKeysigWidth 预扫 + meter slot 滑动。 */}
75+
76+
<Score slug="all-keys" />
77+
78+
</section>
79+
80+
<section data-cue="recap">
81+
82+
{/* TODO: 收。报头是一个假装不动的小宇宙。 */}
83+
84+
</section>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
title: 滚谱的扎法
3+
date: "2026-05-04"
4+
kind: ESSAY
5+
summary: 从 MEI 到一个能在网页里横向滚动、声音同步的乐谱组件。
6+
tint: dune
7+
draft: true
8+
---
9+
10+
import Score from '../../components/Score.astro';
11+
12+
{/*
13+
起草大纲(按 cue 顺序):
14+
15+
why-mei — MEI / MusicXML 是什么。为什么不画 PNG。
16+
Verovio 把 MEI 渲到 SVG 是个起点,但只是起点。
17+
one-system — `breaks: 'none'` 把一首曲子排成一整条横向系统。
18+
天然给"横向滚动"提供了画布。
19+
`pageWidth: 100000, adjustPageHeight: true`。
20+
staff-anchor — viewBox 的坑:bbox 含装饰,装饰多 → staff 被压扁。
21+
解:以 staff body 为锚反推舞台高度(measure 一次,
22+
重设 --score-h,回流,继续)。
23+
本博客的 staffHeight = 40 默认。
24+
tile — Ravel 全曲 SVG 宽 ~37k px,撞 GPU 单纹理上限。
25+
沿小节切 tile(≤4096px),每片自己一个 viewBox
26+
crop,外层 GPU 各管各的。
27+
anchors — 把每个音符的 onset ms 映射到屏幕 x。线性插值 +
28+
游标缓存(O(1) 稳态)。msAtX/xAtMs 双向。
29+
loop — 多份 SVG 副本贴边铺开 + 幻影前导 tile。看到的
30+
seam 都是设计过的。
31+
recap — 整套架构是写给一个人的:作者读自己的谱子的时候
32+
不应该被装饰量影响视觉权重,不应该被 GPU 限制
33+
打到 10fps,不应该听一段需要按 5 个键。
34+
*/}
35+
36+
<section data-cue="why-mei">
37+
38+
{/* TODO: MEI/MusicXML 简介,Verovio 是什么。 */}
39+
40+
</section>
41+
42+
<section data-cue="one-system">
43+
44+
{/* TODO: `breaks: 'none'` 的决定 */}
45+
46+
<Score slug="jeux-deau" />
47+
48+
</section>
49+
50+
<section data-cue="staff-anchor">
51+
52+
{/* TODO: viewBox 含装饰的问题 + staff-anchor 的解。 */}
53+
54+
</section>
55+
56+
<section data-cue="tile">
57+
58+
{/* TODO: GPU 纹理上限 + tile 切片。 */}
59+
60+
<Score slug="jeux-deau-ravel" />
61+
62+
</section>
63+
64+
<section data-cue="anchors">
65+
66+
{/* TODO: msAtX/xAtMs,游标缓存。 */}
67+
68+
</section>
69+
70+
<section data-cue="loop">
71+
72+
{/* TODO: 多副本 + 幻影 leader 的实现。 */}
73+
74+
<Score slug="jeux-deau" loop />
75+
76+
</section>
77+
78+
<section data-cue="recap">
79+
80+
{/* TODO: 收。整套是为读自己的谱子写的。 */}
81+
82+
</section>

src/content/essays/jeux-deau-test.mdx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
---
2-
title: 水之嬉戏(测试)
2+
title: Score 组件测试页
33
date: "2026-04-26"
44
kind: NOTE
5-
summary: Jeux d'eau 简化引文 + 完整 MusicXML 转写,验证乐谱组件全链路。
5+
summary: 全部 5 个 Score 实例集中在一页,用于回归 / 压力测试。永久 dev-only。
6+
draft: true
67
---
78

89
import Score from '../../components/Score.astro';

src/content/essays/pei-pu.mdx

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
title: 陪谱
3+
date: "2026-05-04"
4+
kind: NOTE
5+
summary: 一种横向滚动的乐谱。它不替你看,它陪你看。
6+
tint: plum
7+
draft: true
8+
---
9+
10+
import Score from '../../components/Score.astro';
11+
12+
{/*
13+
起草大纲(按 cue 顺序):
14+
15+
empty — 谱子的常规呈现是一整页静止的方块。问题:你的眼睛得
16+
自己跟节拍跑。读者和音乐永远差着一个滞后。
17+
playhead — 引入"播放头"作为一个确定的位置。它代替你定位"当下
18+
听到的是这一颗"。它不是滚动,是被滚动。
19+
scrolling — 谱面横向移动,播放头不动。这点很重要:眼睛盯一个
20+
固定位置就够了,剩下的交给页面。
21+
frozen — 谱号、调号、拍号永远在最左边,跟你说"现在的语境是
22+
什么"。中间换调号,左边平滑替换;不消失也不闪烁。
23+
loop — 最短的一段也可以反复听。loop 不是退化,是供你停留。
24+
audio — 同时还有声音。不为了演奏,为了让你"知道这里听起来
25+
是什么样的"——尤其当 32 分音符密到你眼睛跟不上的
26+
时候。
27+
reading — 收:这是阅读的姿势,不是演奏的。你不是来识谱的,
28+
你是来跟它过一遍的。
29+
*/}
30+
31+
<section data-cue="empty">
32+
33+
{/* TODO: 静止的谱面 vs 听音乐的时间性。 */}
34+
35+
</section>
36+
37+
<section data-cue="playhead">
38+
39+
{/* TODO: 播放头作为「当下的指认」。 */}
40+
41+
</section>
42+
43+
<section data-cue="scrolling">
44+
45+
{/* TODO: 谱面动 / 头不动 的视觉决策。 */}
46+
47+
<Score slug="jeux-deau" />
48+
49+
</section>
50+
51+
<section data-cue="frozen">
52+
53+
{/* TODO: 报头永远在那里。语境感。 */}
54+
55+
</section>
56+
57+
<section data-cue="loop">
58+
59+
{/* TODO: 短句的反复。陪伴的耐心。 */}
60+
61+
<Score slug="jeux-deau" loop />
62+
63+
</section>
64+
65+
<section data-cue="audio">
66+
67+
{/* TODO: 声音作为"知道这里听起来怎样"。 */}
68+
69+
</section>
70+
71+
<section data-cue="reading">
72+
73+
{/* TODO: 收。这是阅读,不是识谱。 */}
74+
75+
</section>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
title: 水之嬉戏
3+
date: "2026-05-04"
4+
kind: NOTE
5+
summary: 拉威尔 1901 年的水。从一个 Eadd9 落下来。
6+
tint: mist
7+
draft: true
8+
---
9+
10+
import Score from '../../components/Score.astro';
11+
12+
{/*
13+
起草大纲(按 cue 顺序):
14+
15+
empty — 这首曲子的位置:1901 年 Ravel 22 岁,献给 Fauré,钢琴写法
16+
从这里开始转向。一句"水的声音"作为引子。
17+
source — 我为什么动手写四个小节而不是直接用 MusicXML:手写让你
18+
一颗音一颗音地决定,对于这首尤其要紧——它的"水"是 32 分
19+
音符织出来的,每一颗都是清醒的选择。
20+
hand — 简化版本的 Eadd9 引子(4 小节)。指出我从原谱挑了什么、
21+
放弃了什么,原谱 m3 没有变速,我加了两记速度变化是为了
22+
测试 tempo overlay。
23+
loop — loop 模式作为"再听一遍"的隐喻。Ravel 自己的水也是
24+
循环图样,loop 在这里不是退化,是回放。
25+
full — 跳到 MuseScore 转写的完整原谱。从手写到原谱的尺度跳跃
26+
正好是 evocation 到 transcription 的距离。
27+
coda — 听完之后剩下的那一秒:水停了,纸还湿着。
28+
*/}
29+
30+
<section data-cue="empty">
31+
32+
{/* TODO: 1901。Ravel 22 岁。献给 Fauré。「Comme l'eau」(像水那样)。 */}
33+
34+
</section>
35+
36+
<section data-cue="source">
37+
38+
{/* TODO: 手写 vs MusicXML 的选择。「写下来」这个动作本身。 */}
39+
40+
</section>
41+
42+
<section data-cue="hand">
43+
44+
{/* TODO: 简化版引子。说一下我加的两记速度变化只是为了测 overlay。 */}
45+
46+
<Score slug="jeux-deau" />
47+
48+
</section>
49+
50+
<section data-cue="loop">
51+
52+
{/* TODO: 循环作为复听。 */}
53+
54+
<Score slug="jeux-deau" loop />
55+
56+
</section>
57+
58+
<section data-cue="full">
59+
60+
{/* TODO: 跳尺度——从我的手写四小节到全曲。 */}
61+
62+
<Score slug="jeux-deau-ravel" />
63+
64+
</section>
65+
66+
<section data-cue="coda">
67+
68+
{/* TODO: 一两句收。水停了。 */}
69+
70+
</section>

0 commit comments

Comments
 (0)