Your first interactive .md
跟着这篇做完,你会有一个真实可用的复利计算器——含 3 个滑块、自动计算的派生值、随滑块实时重绘的 chart。 全程不写一行 JS,只写 markdown。 预计时间:10 分钟。
你需要的
- 任意 markdown 编辑器(VS Code / Sublime / Obsidian / 普通文本编辑器都行)
- Rho MD app(免费——Windows、Linux、Android)
还没装 Rho?参考 Install Rho app。
我们要做什么
一个复利计算器:
输入本金、年利率、年限 → 实时显示终值 / 净收益 / 增长曲线。
最终它会长这样(伪图):
┌─────────────────────────────────────┐
│ 本金 [────●────────] $10,000 │
│ 年利率 [──●──────────] 5.0% │
│ 年限 [──────●──────] 10 年 │
├─────────────────────────────────────┤
│ 复利终值 = $16,289 │
│ 净收益 = $6,289 │
│ │
│ [增长曲线 chart 实时重绘] │
└─────────────────────────────────────┘
我们不一次性写完——分 6 步加,每步加一个能力。
Step 1:从纯 markdown 开始
先写一份完全没有交互的复利说明文档。新建 compound.md:
# 复利计算器
复利是把上期利息加进本金、下期一起再生利息的计算方式。
公式:
```
终值 = 本金 × (1 + 利率)^年限
```
例子:本金 $10,000、年利率 5%、年限 10 年 → 终值 ≈ $16,289。
在 Rho MD 里打开看效果——只是个普通文档。
读者要算自己的情况,得自己拿计算器。我们要改这个。
Step 2:用 callout 强调公式
公式是核心,单独标出来。把公式段改成 Callout:
# 复利计算器
复利是把上期利息加进本金、下期一起再生利息的计算方式。
> [!INFO]
> **公式**:终值 = 本金 × (1 + 利率)^年限
例子:本金 $10,000、年利率 5%、年限 10 年 → 终值 ≈ $16,289。
刷新看效果——公式现在是蓝色高亮块,扫页时一眼就找得到。
这步学到的:callout 是给"读者必读"的内容加视觉权重。详见 Callout 文档。
Step 3:把"本金"变成滑块
把"$10,000"从死数字变成可拖动滑块。在公式下面加一个 interact 块:
> [!INFO]
> **公式**:终值 = 本金 × (1 + 利率)^年限
```interact
slider principal 1000 100000 10000 1000
template stl:
[本金] -> [${principal:.0f}]
```
刷新——现在屏幕上多了一行可拖动的滑块和一行自动更新的文本:"本金 = $10,000"。拖滑块 → 数字实时变。
语法解读:
slider principal 1000 100000 10000 1000创建一个滑块:变量名principal,最小 1000,最大 100000,初始值 10000,步长 1000template stl:告诉 Rho 接下来是 STL 输出模板${principal:.0f}是 mini DSL 表达式——principal是滑块的当前值,:.0f是格式化(0 位小数)
这步学到的:interact 块 = 控件 + 模板。控件驱动模板里的
{var}占位符。详见 Interact controls 文档。
Step 4:加利率 + 年限滑块 + computed 派生
继续扩展同一个 interact 块——加两个滑块 + 一个 computed 派生值:
```interact
slider principal 1000 100000 10000 1000
slider rate 0 0.15 0.05 0.01
slider years 1 30 10 1
computed compound = principal * pow(1+rate, years)
computed gain = compound - principal
template stl:
[本金] -> [${principal:.0f}] ::mod(rate="{(rate*100):.1f}%", years="{years} 年")
[复利终值] -> [${compound:.0f}]
[净收益] -> [${gain:.0f}]
```
刷新——现在有 3 个滑块 + 3 行实时输出。拖任何一个 slider,所有 3 行都重算重显。
新概念:
computed compound = principal * pow(1+rate, years)—— 派生变量,自动跟随源滑块更新- 派生值可以基于派生值(
gain用了compound)—— Rho 自动算依赖顺序 - 表达式 mini DSL 支持
+ - * / pow sqrt sin cos pi log exp等基础运算
⚠️ 注意 mini DSL 不是 JavaScript——它只支持安全的纯函数运算,没有
eval、没有 IO、没有 DOM 访问。这是 Rho 的安全设计。
这步学到的:
computed让交互不止"显示输入值"——能真正算东西。详见 Computed 文档。
Step 5:加 live chart
数字看着满意,但长期增长有多陡?加一个随利率/年限实时重绘的 chart。在同一 interact 块里把 template 从 stl 换成 vega-lite,或者新加一个块:
```interact
slider principal 1000 100000 10000 1000
slider rate 0 0.15 0.05 0.01
slider years 1 30 10 1
computed compound = principal * pow(1+rate, years)
computed gain = compound - principal
template stl:
[本金] -> [${principal:.0f}] ::mod(rate="{(rate*100):.1f}%", years="{years} 年")
[复利终值] -> [${compound:.0f}]
[净收益] -> [${gain:.0f}]
```
```interact
slider principal 1000 100000 10000 1000
slider rate 0 0.15 0.05 0.01
slider years 1 30 10 1
template vega-lite:
{
"data": {"sequence": {"start": 0, "stop": {years}, "step": 1, "as": "year"}},
"transform": [
{"calculate": "{principal} * pow(1+{rate}, datum.year)", "as": "value"}
],
"mark": {"type": "line", "point": true},
"encoding": {
"x": {"field": "year", "type": "quantitative", "title": "年份"},
"y": {"field": "value", "type": "quantitative", "title": "金额 ($)"}
}
}
```
刷新——现在第二块是一条增长曲线,年份做 x、金额做 y。拖任何滑块,曲线实时重绘。
问题:滑块写了两遍(每个块一份),而且两个块的滑块是独立的——拖第一块的滑块不影响第二块的 chart。
下一步解决。
Step 6:用 namespace 共享 state
加一行 namespace finance 让两个块共享同一组变量:
```interact namespace finance
slider principal 1000 100000 10000 1000
slider rate 0 0.15 0.05 0.01
slider years 1 30 10 1
computed compound = principal * pow(1+rate, years)
computed gain = compound - principal
template stl:
[本金] -> [${principal:.0f}] ::mod(rate="{(rate*100):.1f}%", years="{years} 年")
[复利终值] -> [${compound:.0f}]
[净收益] -> [${gain:.0f}]
```
```interact namespace finance
template vega-lite:
{
"data": {"sequence": {"start": 0, "stop": {years}, "step": 1, "as": "year"}},
"transform": [
{"calculate": "{principal} * pow(1+{rate}, datum.year)", "as": "value"}
],
"mark": {"type": "line", "point": true},
"encoding": {
"x": {"field": "year", "type": "quantitative", "title": "年份"},
"y": {"field": "value", "type": "quantitative", "title": "金额 ($)"}
}
}
```
注意第二块只有 template,没有 sliders / computed——它复用 namespace finance 里第一块定义的所有变量。
刷新——现在拖任何一个滑块,文本和 chart 同时更新。
这步学到的:
namespace让多个 interact 块共享 state——避免重复定义。详见 Shared state 文档。
Step 7(可选):用 layout 把它做漂亮
最后用 Layout grid + cards 把控件 + 输出 + chart 按 2 列布局:
# 复利计算器
> [!INFO]
> **公式**:终值 = 本金 × (1 + 利率)^年限
```layout grid cols=2
:::card accent=blue
**输入参数**
\```interact namespace finance
slider principal 1000 100000 10000 1000
slider rate 0 0.15 0.05 0.01
slider years 1 30 10 1
computed compound = principal * pow(1+rate, years)
computed gain = compound - principal
template stl:
[本金] -> [${principal:.0f}]
[复利终值] -> [${compound:.0f}]
[净收益] -> [${gain:.0f}]
\```
:::
:::card accent=green
**增长曲线**
\```interact namespace finance
template vega-lite:
{
"data": {"sequence": {"start": 0, "stop": {years}, "step": 1, "as": "year"}},
"transform": [{"calculate": "{principal} * pow(1+{rate}, datum.year)", "as": "value"}],
"mark": {"type": "line", "point": true},
"encoding": {"x": {"field": "year"}, "y": {"field": "value", "type": "quantitative"}}
}
\```
:::
```
刷新——现在它像个产品了:左侧蓝卡控件 + 输出,右侧绿卡 chart,整页清爽对称。
这步学到的:任意块可嵌套任意块——layout 套 interact、callout 套 interact、stepper 套 layout 都行。详见 Nested DSL 文档。
你做完了什么
10 分钟里你用了 Rho 的 5 项能力:
| 能力 | 在哪 |
|---|---|
Callout (> [!INFO]) |
公式高亮 |
| Layout grid + cards | 双列布局 |
| Interact controls (slider) | 3 个滑块 |
| Interact text template (stl) | 文本输出 |
| Interact + Vega-Lite | 增长曲线 |
| Computed | compound / gain 派生 |
Shared state (namespace) |
文本块和 chart 块共享变量 |
| Nested DSL | layout 里嵌 interact |
整个文档没有一行 JS——纯声明式。任何懂 markdown 的人都能改。
Plain-text fallback 验证
把这份 compound.md 在不支持 Rho 的 reader 里打开(GitHub web / VS Code 默认预览 / cat):
- 公式 callout:在 GitHub 上仍正常渲染(GFM 兼容标准 callout)
- Layout cards:
:::card显示为字面量,但卡片内的 markdown(粗体、列表)正常 - Interact 块:显示为带
interactlang 的代码块——读者看得到 sliders / computed / template,能猜到这文档原本是交互式的
读者永远不会看到坏掉的白屏——这是 Rho 的核心承诺。
接下来
| 你想…… | 入口 |
|---|---|
| 把这个例子玩出花 | 改 chart type、加 toggle 切对比方案、加 timer 自动播放… |
| 看更多 demo(30+ 完整例子) | → Examples gallery |
| 系统学每个能力 | → Writer's Guide |
| 查某个具体语法 | → AINP 协议(v0.7) |
| 把 Rho 集成到自己的 reader | → Developer Reference |
| 让 LLM 帮你生成 Rho 文档 | → Rho AI / LLM Guide |
See also
- What is Rho? — 哲学背景
- 5-minute tour — 15 capability 速览
- Callout
- Layout grid + cards
- Interact controls
- Computed
- Vega-Lite live chart
- Shared state (namespace)
- Nested DSL