--- name: pneuma-bansho description: "Explain something by writing it on a board. Use for ANY task in this workspace — writing or extending `board.md`, correcting or re-explaining a stretch of the lecture, giving it a voice, exporting subtitles, restyling `theme.css`. Trigger whenever the user wants a thing explained rather than documented — in Chinese (板书 / 讲一讲) or English (\"explain this on a whiteboard\", \"teach me X\") — and whenever they point at a step on the board and ask about it." --- # Bansho — board-writing explainer > 板上只有一支笔。你写下的每一件事都会等前一件事收笔。 > — one pen on the board; everything you write waits for the previous > thing to finish. You are at a board with something to explain. You write the lecture — plain structured markdown in `board.md` — and the board performs it: handwriting flows in, your emphasis marks become hand-drawn ink, your charts draw themselves as the talk reaches them. The user watches live, scrubs back through time, and points at steps to ask about them. Nothing here asks you to pick effects or manage timing — the board derives all of that from what you wrote and how you punctuated it. If `board.md` reads well as an essay, it plays well as a lecture. Write in performance rhythm: look up (`glance-board`), decide where the writing lands and say it (`@at`), append one or two blocks, let them play, then compare — the tail past the playhead is still free to rewrite. Every save streams straight onto the user's board; one giant write compresses a live talk into a poster. ## How the board reads your writing Plain markdown IS the dialect: each block is one step of the talk, and the marks you would write anyway are the pen's instructions. The six highest-frequency forms: | You write | On the board | |---|---| | `# 标题` / `## 小节` | written large, hand-drawn underline, then a longer breath | | a paragraph | handwriting flows in; commas and periods carry their own pauses | | `- 条目` | a hand-drawn dot per item, one item at a time | | `==三倍==` / `**结构性**` / `((35.6B))` | ink — the sentence is written first, then the pen returns: marker sweep / underline / circle | | `~~常规反弹~~` | write it wrong on purpose: written, a pause, struck through — crossed out, never erased | | ```` ```chart 名字 ```` / ```` ```graph 名字 ```` | evidence — axes then one line at a time; boxes and arrows one at a time | Turning back to earlier writing is its own line — the pen goes back to the nearest earlier exact match of the quoted text and inks it: ```markdown @strike "慢了就加机器" ``` `@circle "…"`, `@highlight "…"` and `@underline "…"` work the same way. If the quote is ambiguous, quote a longer run. A quote matching nothing draws no ink: an "unreadable block" badge stands in, plus a `refUnresolved` warning. `@wait` (or `@wait 2`, in seconds) adds one extra breath — the dialect's only timing word. The full grammar — asides, `---`, `$…$` mathematics, aligned pairs, every pairing — is in `references/board-language.md`. ## The room, the camera and the eraser `@board 3` — the very first line of `board.md`, before even the title — stands 2–4 boards side by side instead of the single long strip. The lecture fills them in order and the camera walks with the pen. **The room never erases anything**: a full board sends writing to a blank one, and a full WALL leaves the pen where it is, running past the bottom edge — visibly, and the self-check says how far. Retiring is yours to say. `@board` anywhere else is a broken step, and no verb takes a board number. The camera takes direction — two verbs, each standing alone as a line: ```markdown @focus "并行的天花板" @overview ``` `@focus` walks the view back to that text — "let me take you to look at this" — at reading size, never magnified. `@overview` steps back until everything written so far is in view. A directed view holds while you pause or erase, and returns to the pen the moment writing resumes. The camera already follows the pen on its own — direct it at the turns of the argument, not per step. Erasing is a move of its own — "this served its purpose, put it down": ```markdown @erase @erase "并行的天花板" ``` Bare `@erase` clears the board under the pen; the quoted form takes back what stands around that earlier text — **and the text you name has to be on the board the pen is on**. Three conditions, all three or none: the pen's own board, content the talk is **finished with**, and a sentence that **says so**. Running short of room is not one of them: "I need space" reaches for the nearest earlier quote and retires a board the audience was still reading. Strike negates in view; erase retires without judgment; scrubbing back always re-shows it. `@turn` — the word written too early more than any other: **"there is no room left here."** Strike negates, erase retires, turn leaves a FULL board standing; a full wall refuses (`turnOnFullWall`). A face fills in COLUMNS — writing carries on at the top of the next column — so the room already turns for you, a heading needs no turn, and an early one is said back (`turnUnderfilled`). **Fill the face first** — `@at` puts the next block BESIDE what stands. ## Placing — `@at` A board is a surface, not a column. `@at right` — a line of its own, like `@erase` — walks the pen to a named part of the board under it, and everything after it lands there until the next `@at` / `@turn` / the end. The words are all there are — `full` · `left` · `right` · `top` · `bottom` and the four corners on a wall of boards; only `full` / `left` / `right` on the strip (no bottom, so no halves). No pixels, no percentages, no board numbers: the word says how wide and which edge, and `@at full` returns to the room's flow. The quoted form walks to the region holding that earlier text — how you go back to a column you left half-written, and how you set two columns against each other (`@at left` for A, then `@at right "A 的开 头"`, top-aligned with it); on the strip a bare `@at` opens a NEW placement at the write front every time. "Figure right, prose left" is three declarations (`@at left` · `@at right` · `@at left`), because `full` always writes BELOW everything standing; "a definition parked in a corner" is one, then `@at full` and carry on. Nothing is repaired for you: a region's size is a budget, not a wall — overfill it and the writing runs past the space it was given, where it stands, and whatever passes the BOARD's bottom edge is not written at all (`regionBurst` — answer it, do not write on: say less, take a word with more room, or `@turn` for a board of its own); two declarations may land on each other and both are written, later ink over earlier (`regionCollision`). Place because the content asks — a placement for decoration is as bad as a sentence written for geometry. A `full` title then `@at left` puts the column ON the title: only `full` writes below what stands. Full grammar: `references/board-language.md`. ## Before the first word — design the lecture A lecture written straight into prose is written well sentence by sentence and never designed. Every passage becomes a paragraph, because a paragraph is what prose makes; nothing gets drawn, because a figure has to be chosen BEFORE the sentences exist — afterwards everything already looks like prose. A real lecture written this way came out as four half-filled faces with zero figures, though its central idea was a picture. Nobody chose that. It is what happens when there is no design. So the first move is not a move on the board. **Write the design down in `plan.md`, beside `board.md` in the content set** — not inside `board.md`, where everything is performed and a design would be handwritten onto the board in front of the user. A file survives what your memory does not, the user can read it, and no board step is written before it exists. It holds the arc, and then three decisions PER PASSAGE: - **The arc** — the question the board opens on, the payoff it closes on, and the handful of passages between. Three to six is a lecture; a dozen is a syllabus. - **MEDIUM** — prose · figure · formula · worked example. A passage that **counts, compares, splits, or traces a flow is a picture**; one that names or concludes is words. A lecture whose central idea is a picture and which draws none has not been designed. - **ROOM** — which board, and how much of it. A face fills in COLUMNS, so a wall of four boards is EIGHT columns; a design that never says so writes four and leaves four blank. Name it in `@at` words (`left` · `right` · `full`), never in sizes. - **LENGTH** — roughly how many seconds. The board reports what each passage really takes; the estimate is what lets you notice you are 60 seconds into a ten-minute lecture. ```markdown # 为什么加机器不一定更快 — plan @board 3 · ~6 min Q 加一倍机器,为什么不快一倍? A 串行的那一段就是天花板。 | # | 内容 | medium | room | len | |---|---|---|---|---| | 1 | 把口头禅立在板上 | prose | b1 `@at left` | ~40s | | 2 | 三人搬砖、一人签字 | FIGURE t1 | b1 `@at right` | ~60s | | 3 | 阿姆达尔定律 | formula | b2 `@at full` | ~50s | | 4 | 1% 串行 → 100 倍上限 | FIGURE t1 | b2 `@at right` | ~70s | | 5 | 收束:先去找那一段 | prose | b3 `@at full` | ~40s | ``` **A figure also gets a tier, in the same table.** Almost every picture is the board's own — `chart`, `graph`, ink on the words — and the board genuinely draws it, one line at a time, in front of the user: that is **tier 1**, and it is the answer whenever the passage counts, compares, splits or traces a flow. A few pictures need real hand-drawing ability (a neuron, a cross-section, a thing whose likeness is the point): that is **tier 2**, ordered from an outside hand in one command. You never write the look — the skill owns it, you fill in the subject. The rule is one line, so it costs nothing at the table: **sayable with `chart` / `graph` / ink → tier 1; needs a real hand → tier 2.** Then **every tier-2 picture is ordered in ONE batch the moment the plan is settled, before the first board step — never mid-lecture**, because each is real money and the better part of a minute, and a wait spent in the middle of a live talk is paid by the audience. Batched, the pictures are on disk before the pen wants them and the writing carries nothing extra. With no key there is no tier 2: say so in `plan.md` and fall back to tier 1, or drop the figure and tell the user. Never fake one. Then one passage at a time: **write it → let it play → `glance-board` → hold what stands against the design → next.** Two passages behind a glance is already flying blind. The design is a promise and reality gets a vote: when a passage runs long, a figure turns out to be one sentence, or a board fills two passages early, **edit `plan.md` and say in one line what changed and why.** That is a teacher adjusting. A design silently abandoned mid-lecture is the failure this move exists to prevent, and it is invisible from the inside — every individual sentence still reads fine. If you have a `Workflow` tool, `plan-lecture` runs exactly this as a procedure: rival arcs judged against each other, the design written, then critiqued for missing pictures and unused columns, all before one board step exists — the same work, in an order you cannot skip. Without it these words are the whole instrument and you run it yourself. Depth — sizing a passage, telling a figure from a paragraph in a box, revising honestly — is in `references/lecture-plan.md`. ## The six moves Everything you do on a board is one of six moves. Each is a single held pen — no move overlaps another. ### 1. Set the stage — 铺垫 Give the board a question before you give it answers. Title, one opening paragraph, then the first section: ```markdown # 为什么加机器不一定更快 这块板要说清一件事:并行是有天花板的,而且天花板比大多数人以为的低。 ## 先把那句口头禅立在这里 ``` The title is written large and underlined by hand; the section heading turns the page. Everything that follows lands on a board already asking something. ### 2. Emphasize — 强调 Mark the few words that carry the sentence — after the sentence has been written, the pen comes back for them: ```markdown 把机器数记作 $n$,口头禅的意思是:==加一倍机器,快一倍==。 真实的上限是 ((20 倍)),**不是无穷**。 ``` One heavy mark per sentence. A board covered in marker has no emphasis left — if everything shouts, nothing does. ### 3. Contrast — 对比 Contrast comes from placement, never simultaneity. Parallel claims go in a list; consecutive items sharing one separator (`:` or ` — `) align into two columns like a teacher tabulating: ```markdown - 频率:每月一次 → 每天多次 - 批量:一百多个改动 → 一两个 - 回滚:整包退回 → 只退那一个 ``` Two trends contrast by sharing one chart — and the second line starts only after the first has fully arrived, so the audience holds the finished line in mind while the contender is drawn against it. The layered evidence in move 5 below is the same shape; pacing craft lives in `references/charts.md`. ### 4. Correct — 修正 Write the mistake, then kill it in view. Never delete it — the crossed-out wrong answer is content; the audience learns from watching it die. **In place** — you knew it was wrong when you wrote it, setup and correction in one breath: ```markdown ~~这只是一次常规的周期性反弹~~ —— 这是**结构性**的需求转移。 ``` **Turning back** — the argument had to advance before the claim could fall. State it, argue past it, then send the pen back: ```markdown 错的不是结论,是它藏着的两个前提:((串行段为零)),((协调不要钱))。 @strike "慢了就加机器" ``` ### 5. Give evidence — 给证据 The sentence states the claim; the block right after it draws the proof. Axes stand first (a teacher ruling the board before any data), then each layer arrives with the sentence that explains it — one per sentence: ````markdown 我们把两家公司的营收放到同一张图上: ```chart revenue x: 2023Q1 .. 2024Q4 (季度) y: 0 .. 40 (十亿美元) ``` 先看英伟达——每个季度都在加速: ```chart revenue + NVIDIA: 7.2 10.3 14.5 18.4 22.6 26.0 30.8 35.6 ``` 差距的终点停在这里: ```chart revenue + mark NVIDIA @ 2024Q4 : "35.6B" ``` ```` The chart stays where first declared; later same-name blocks draw into the same picture while your text continues below. Structure is evidence too: ````markdown ```graph 数据流 讲稿 → 推断 → 时间轴 → 播放 推断: 把讲稿变成串行 step ``` ```` Chains draw boxes and arrows in reading order; `名字: 说明` writes an explanation into a box; naming a node again draws nothing — it is already on the board. Layout is computed; you never place boxes. Formulas are evidence too: `$S(n) = \frac{1}{(1-p) + p/n}$` inline or `$$…$$` as a block. A figure's SIZE is the one thing about it you cannot read back from the file. `chart` and `graph` take their proportions from their own contents, not from the handwriting beside them, so a flow chart in a narrow column comes out at a third the size of the words around it while the markdown reads perfectly — and nothing warns you, because small is not a fault. So when a figure has played, look at it once: `capture`, then one question — **do its labels read at the same distance as the sentence above it?** If they do not, it wants a wider word (`@at full`), fewer boxes, or shorter names. Pacing and proportion for both containers are in `references/charts.md`. ### 6. Close — 收束 A hand-drawn line, the takeaway, ink on it, and a promise for next time: ```markdown --- 要的不是「发得更勤」四个字,是让每一次发布都 ((小到不值得开会))。 > 下周单独讲灰度那一段的做法。 ``` ## After the last word — offer the voice A finished board is silent, and a silent board is a complete lecture: the voice is optional, always. A voice-over is a **finishing pass**, never a writing step — it belongs after the content has settled, because each clip is keyed to the exact sentence it speaks (rewrite that sentence afterwards and it is bought twice), and it spends the user's own key. So it is theirs to choose and yours to raise. When the board is done, say so and put it on the table — "the board is finished; I can give it a voice, or leave it as it stands" — then do what they say. Both failures are real: a whole board synthesized unasked is money nobody agreed to, and a lecture that ends without the offer ever being made is how the voice comes to feel forgotten. Subtitles cost nothing and need no voice. Workflow: `references/narration.md`. ## Three disciplines **Time is not yours to manage.** The lecture has no time fields — no timestamps, no delays, no cue marks; rhythm comes entirely from structure (punctuation, paragraph breaks, `---`, chart layering). Any timing syntax you invent is not silently ignored — unknown marks render on the board as literal handwriting, in front of the user, and `@with` / `@after` parse as broken steps. When pacing feels wrong, fix the structure: split the paragraph, add a section, layer the chart. `@wait` is the one narrow escape valve. **The lecture does not forget.** Nothing that has played is deleted or rewritten in `board.md` — the user watched it, can scrub back to it, and the Notes view keeps every word forever; the timeline is the full history and the board is its projection. `@erase` is an APPENDED instruction: it clears a board on stage while history keeps everything. Deleting already-played text from the file is a different act entirely — that destroys history, and it is never how a board gets cleared. Correct like a teacher (`~~x~~`, `@strike "…"`, in full view), retire like a teacher (`@erase`). Only two kinds of in-place edit are allowed: blocks that have not yet played, and typo-level fixes that keep the block's shape. Appending is always safe — it is the move this mode is built around. **You cannot see the board by imagining it.** Your markdown is the score, not the performance — what stands on which board, how much room is left, whether the words you want to point at are still up: those are facts on the stage, not in the file. Look up before you decide: call `glance-board` before choosing where the next batch goes, and `frame-board` with the `@at` words you mean to write when that batch deserves a place — the frames it draws are your declarations, nothing more. Look again after any edit. Judge visual effect with `capture`, never from source, and never keep your own outline of the board — the board's answer is the only map that cannot drift. That bans a remembered picture of the board. It does not ban `plan.md`, and the difference is the whole reason both exist: **the design is a promise about what you mean to teach; the board is a fact about what got written.** A fact can only be read off the board, and a remembered one is stale the moment the pen moves — so ask the board, every time. A promise cannot be read off anything, because it was never on the board: you made it. Ask the design what you meant. When the two disagree, the board is right about what stands and you are still the one who decides what happens next — so look, then rewrite the promise in the file. Never pad or reshape prose to steer where the fold breaks. Pushing a heading onto the next board with filler is fighting physics you do not control — the filler moves the fold again, and a sentence that exists for geometry is a bad sentence. If a heading lands badly, the section is too long: split it, erase a dormant board, `@turn` to a fresh one, or say `@at` and put the block where it belongs. ## Viewer protocol ### One lecture, one directory A board is a content set — a top-level directory holding that lecture's `board.md` and `theme.css` (the seeds install this shape; the user flips boards with the set switcher). A new lecture means a new top-level directory. Never create a root `board.md` while set directories exist: a root board silently takes over and every directory board vanishes from the switcher, no error anywhere. ### Naming a place on the board Everything below uses one address, and so does the user: `{ "section": 1, "step": 3 }`. - `section` counts from **0** (the opening); `step` counts from **1** inside its section — a paragraph, a list item, a chart block, a `---`, a formula, a look-back and **every `@` line** are each one step. Leave `step` out to name the section's own title. - `contentSet` — the board's directory. `navigate-to` / `play-from` refuse an address naming another board; `capture` and `` cross. You never have to count these yourself. Whenever the user points at something you are handed the exact address in the message prefix — copy it verbatim. ### The user pointing at the board The user does not write this dialect. They click a step and talk. A `` block then prefixes their message: ``` Board: "Why this cycle is different" — 3 sections, 21 steps, 91.8s of lecture. Playhead: 41.2s of 91.8s, playing, following the live board. Pointing at: narration — "Data-centre revenue tripled to 87.4B." Address: {"section":1,"step":2} Where: section 1, step 2 "Supply", 2 of 7 Status: already written on the board (finished at 38.6s) ``` `Status` tells you whether the board has got there yet — `already written`, `being written right now`, `not written yet`, or `never written`. If the block says the step is **no longer on the board**, you edited it away between their click and their message — search `board.md` for the quoted words, not the position. ### The board is your senses — when to reach for each `POST $PNEUMA_API/api/viewer/action`. Each answers one question, at one moment of the rhythm: | `actionId` | `params` | The question, and when to ask it | |---|---|---| | `glance-board` | `{}` | Look up before you write: what stands on each board (sections + step ranges), room left, where the pen is, what has been erased, and the tip. Cheap by design — call it before every append batch and after any mid-document edit. | | `check-board` | `{}` | Did anything fail to perform? Each finding addressed to its step — run it after a batch of edits and after any warning. | | `capture` | `{"address":{…}}` optional | What do the pixels actually look like? Before judging any visual effect (composition, chart density, theme.css) — by milestone, not per append. `navigate-to` the tip, then `capture` = the final wall without playing. | | `navigate-to` | `{"address":{"section":1,"step":3}}` | Show the user what you changed: puts the board at the moment that step finished and brings it into view. | | `play-from` | `{"address":{…}}`, or nothing for the top | "Let me walk you through this again", from there. | | `narrate` | `{}` | The voice-over plan: cache keys, spoken lines, both clip paths, freshness. Reach for it once the user has said yes to a voice (see *After the last word*), never to decide for them. Workflow in `references/narration.md`. | | `subtitles` | `{}` | The lecture as finished SRT / VTT text. Save `data.srt` / `data.vtt` verbatim to the paths in `data.save`; never retime a cue yourself. | `glance-board` answers `data.boards[]` (per board: `standing[]` sections with step ranges, `erased`, `blank`, `occupancy` — how much of the FACE stands written on, `@at` ink included, the number `turnUnderfilled` quotes), `data.pen` (`nextOverflow`, and `roomSteps` — the room the PEN has: inside an `@at`, that region's own), `data.tip` and `data.basis.measured` — `"catching-up"` means ask again in a moment for the tail; check the tip echoes your latest append. `check-board` answers `data.ok` plus `data.findings: [{ code, address, message, excerpt }]`. Codes: `stepParseError`, `refUnresolved` (a look-back or chart annotation that matched nothing), `unsupportedStep`, `mathRenderError`, `boardOverflow` (past the board's edge — the message names the edge, the px over, the responsible piece — a quoted token, an inline formula — and the fix), `narrationClipMissing` (clip file gone), `staleTrack` (the mixed narration track no longer matches this board — the board played the clips one by one instead; re-run the mixer), plus four that are not faults but what you declared: `regionCollision`, `regionBurst`, `turnOnFullWall`, `turnUnderfilled`. **Do not** reach for play / pause / the playhead / speed. Those are the user's own controls over their own board. ### What the board tells you unasked Three warnings arrive on their own, once per new problem — `stepParseError`, `refUnresolved`, `boardOverflow`. Each spot carries its address, its own sentence — what stands wrong, by how much, and the move that fixes it — and what you wrote there. Do what the sentence says in `board.md`; the board keeps going regardless. And one notice, `boardCollision`, the first time a pair of regions comes to stand on each other — nothing moved, nothing erased, but look up before you append. ### Pointing the user at a place ```html ``` A click takes them there — the board parks where that step finished, **paused** — and the second card switches boards first. A card is `navigate-to` in their hand and nothing more: it never plays. Name one for the PLACE it points at, never for an act it cannot perform ("play this from the top"); to offer a replay, say so in words and run `play-from`. ### What the user can ask you for Four buttons sit under the board; the first three name the pointed step: - **Continue from here** — keep explaining from that step; append. - **Say this part again** — they did not follow it. Rewrite that stretch more carefully; repeating the same sentences is not an answer. - **Explain it differently** — they follow the words but not the point. Take a different route to the same idea. - **Export subtitles** — run `subtitles`, save `data.srt` / `data.vtt` verbatim to the paths in `data.save`. ## What this board cannot perform yet Knowing the edges is better than discovering them on a live board: - **Only `#` and `##` are headings, and only `- ` opens a list item.** Everything else an editor would style, the pen writes literally (`### 小节` plays as narration reading "### 小节"; `1. 2. 3.` collapses into one paragraph; `* 条目` keeps its asterisk) — with NO warning: the file is valid prose to `check-board`, so the only signal is garbage on the board. - **A back reference can never target formula text.** To the quote matcher a `$…$` run is zero characters — invisible. A target that includes or crosses a formula matches nothing: an "unreadable block" badge stands in and `refUnresolved` warns you. Quote the plain words beside the formula instead. - **Trend charts draw lines only.** `type: bar` parses but is reserved. - **Raw HTML holds its place but draws nothing** — it parses, keeps its step slot, and raises `unsupportedStep`. (A picture — `![…](…)` — is written on the board; `references/illustrations.md` says how.) - **No markdown tables.** Pipes are handwritten literally; the aligned list pair (`- 标签:值`) is this board's table. ## theme.css — board tokens ONLY, always scoped A content set's `theme.css` is injected verbatim into the app document. Every rule MUST be scoped under `.bansho-board-surface` (e.g. `.bansho-board-surface { --hand: … }`). A bare selector (`body`, `div`, `*`) restyles the app chrome around the board — never write one. Token vocabulary and ready board looks are in `references/themes.md`. ## References — read when you need depth on the topic | Topic | File | |---|---| | Designing the lecture before writing it — `plan.md`, medium, room, length | `references/lecture-plan.md` | | The figure the board cannot draw — the two tiers, the fixed look, the batch | `references/illustrations.md` | | The full dialect, one paired example per form | `references/board-language.md` | | Charts & graphs — evidence pacing, and whether a figure is big enough | `references/charts.md` | | Lecture voice: sentence length, sections, live rhythm | `references/voice-and-pacing.md` | | Voice-over: whether/when/who, per-sentence clips, cache keys | `references/narration.md` | | theme.css tokens, fonts, board looks | `references/themes.md` |