File size: 17,369 Bytes
f56a29b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | ## Whiteboard Reference
### Canvas Specifications
**Dimensions**: 1000 Γ 563 pixels.
**Coordinate system**: `x = 0` at the left edge, `x = 1000` at the right edge. `y = 0` at the top, `y = 563` at the bottom. Every element has `(left, top)` at its top-left corner.
**Safe zone**: keep content within `x β [20, 980]` and `y β [20, 543]` to leave a 20px margin from the canvas edges.
**Reference points**:
- Centered horizontally: `x = (1000 - width) / 2`
- Centered vertically: `y = (563 - height) / 2`
- Two-column layout: left column `x β [20, 480]`, right column `x β [520, 980]` (40px gutter)
### JSON Output Context
Whiteboard actions are `{"type":"action","name":"wb_...", "params":{...}}` items inside the JSON array your response is required to be. All positions are integers (or decimals accepted, but stay in pixel units).
**LaTeX fields deserve special care β see the "LaTeX JSON Escape" section below.**
### Action Reference
For every whiteboard action, the JSON shape below is the **complete, canonical** form. All other prose in this file assumes these shapes.
#### wb_open
Open the whiteboard before drawing. Once open, `wb_draw_*` calls auto-render.
```json
{"type":"action","name":"wb_open","params":{}}
```
No parameters. Call before any `wb_draw_*`. Not required before every `wb_draw_*` β only once at the start of a drawing phase.
#### wb_draw_text
Place plain text. Use for notes, steps, labels β **not** for math formulas (use `wb_draw_latex` instead).
```json
{"type":"action","name":"wb_draw_text","params":{"content":"Step 1: identify forces","x":60,"y":60,"width":600,"height":43,"fontSize":18,"color":"#333333"}}
```
| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string | yes | Plain text or HTML `<p>` block. No LaTeX commands. |
| `x` | number | yes | Left edge in pixels. |
| `y` | number | yes | Top edge in pixels. |
| `width` | number | no (default 400) | Text container width. |
| `height` | number | no (default 100) | Text container height. Use the Font Size Table below to pick a matching height. |
| `fontSize` | number | no (default 18) | Point size. Pick from the Font Size Table. |
| `color` | string | no (default `#333333`) | Hex color. |
| `elementId` | string | no | Stable ID for later `wb_delete`. |
**Common mistake**: embedding LaTeX like `"content":"\\frac{a}{b}"` in a text element β KaTeX is NOT run on text content, so the raw backslash prints. Use `wb_draw_latex` for any math.
#### wb_draw_shape
Place a geometric shape. Use for annotations, groupings, or simple diagrams.
```json
{"type":"action","name":"wb_draw_shape","params":{"shape":"rectangle","x":60,"y":200,"width":200,"height":100,"fillColor":"#5b9bd5"}}
```
| Field | Type | Required | Description |
|---|---|---|---|
| `shape` | `"rectangle"` \| `"circle"` \| `"triangle"` | yes | Primitive shape. |
| `x`, `y` | number | yes | Top-left of the shape's bounding box. |
| `width`, `height` | number | yes | Bounding box size. |
| `fillColor` | string | no (default `#5b9bd5`) | Hex fill color. |
| `elementId` | string | no | Stable ID. |
**Common mistake**: drawing a "parabola" as `wb_draw_shape` with `shape:"triangle"` or as a sequence of `wb_draw_line` segments. Neither renders a curve β there is no function-plot primitive. Prefer explaining algebraically or with a table of key points until this gap is closed.
#### wb_draw_line
Draw a straight line or arrow.
```json
{"type":"action","name":"wb_draw_line","params":{"startX":100,"startY":300,"endX":400,"endY":300,"color":"#333333","width":2,"points":["","arrow"]}}
```
| Field | Type | Required | Description |
|---|---|---|---|
| `startX`, `startY` | number | yes | Start coordinates. |
| `endX`, `endY` | number | yes | End coordinates. |
| `color` | string | no (default `#333333`) | Hex color. |
| `width` | number | no (default 2) | **Stroke thickness**, NOT line length. Keep 2β4. |
| `style` | `"solid"` \| `"dashed"` | no (default `"solid"`) | Line style. |
| `points` | `[start, end]` of `""` or `"arrow"` | no (default `["",""]`) | Arrow markers at each end. |
| `elementId` | string | no | Stable ID. |
**Common mistake**: setting `width` to the desired span (e.g., 300). `width` is stroke thickness; arrow markers scale with it β `width:60` produces a 180Γ180 arrowhead.
#### wb_draw_latex
Render a math formula via KaTeX.
```json
{"type":"action","name":"wb_draw_latex","params":{"latex":"\\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}","x":100,"y":80,"height":80}}
```
| Field | Type | Required | Description |
|---|---|---|---|
| `latex` | string | yes | LaTeX source. **Every `\` must be written as `\\` in the JSON string β see "LaTeX JSON Escape" below.** |
| `x`, `y` | number | yes | Top-left. |
| `height` | number | no (default 80) | Preferred rendered height. See the LaTeX Element Height Table below. |
| `width` | number | no (default 400) | Max horizontal space. Auto-computed from height Γ aspect ratio unless this cap kicks in. |
| `color` | string | no (default `#000000`) | Hex color. |
| `elementId` | string | no | Stable ID. |
**Most common mistake**: single-backslash commands. If your rendered board shows literal words like `ext`, `heta`, `imes`, `rac`, `ightarrow`, that is the bug. Next response: rewrite with `\\text`, `\\theta`, etc.
#### wb_draw_chart
Render a data chart.
```json
{"type":"action","name":"wb_draw_chart","params":{"chartType":"bar","x":100,"y":150,"width":500,"height":300,"data":{"labels":["Q1","Q2","Q3"],"legends":["Sales"],"series":[[100,120,140]]}}}
```
| Field | Type | Required | Description |
|---|---|---|---|
| `chartType` | `"bar"` \| `"column"` \| `"line"` \| `"pie"` \| `"ring"` \| `"area"` \| `"radar"` \| `"scatter"` | yes | Chart kind. |
| `x`, `y`, `width`, `height` | number | yes | Bounding box. |
| `data.labels` | string[] | yes | X-axis labels. |
| `data.legends` | string[] | yes | Series names (one per row in `series`). |
| `data.series` | number[][] | yes | One inner array per legend, length matches `labels`. |
| `themeColors` | string[] | no | Palette override. |
| `elementId` | string | no | Stable ID. |
**Common mistake**: placing a chart that extends past `x + width = 1000` or `y + height = 563` β charts silently clip at canvas edges.
#### wb_draw_table
Render a simple table.
```json
{"type":"action","name":"wb_draw_table","params":{"x":100,"y":200,"width":500,"height":150,"data":[["Variable","Meaning"],["a","Coefficient of xΒ²"],["b","Coefficient of x"],["c","Constant term"]]}}
```
| Field | Type | Required | Description |
|---|---|---|---|
| `x`, `y`, `width`, `height` | number | yes | Bounding box. |
| `data` | string[][] | yes | 2D array. First row is header. All rows same length. |
| `outline` | `{width, style, color}` | no | Border style. |
| `theme` | `{color}` | no | Header color. |
| `elementId` | string | no | Stable ID. |
**Common mistake**: putting LaTeX into table cells (`"data":[["y = \\frac{1}{2}"]]`). Cell text is rendered as plain text; the backslashes stay. Put the formula in a separate `wb_draw_latex` adjacent to the table.
#### wb_draw_code
Draw a code block with syntax highlighting. Includes a ~32px header bar.
```json
{"type":"action","name":"wb_draw_code","params":{"language":"python","code":"def greet(name):\n print(f'Hello, {name}')","x":100,"y":120,"width":500,"height":120,"fileName":"hello.py","elementId":"code1"}}
```
| Field | Type | Required | Description |
|---|---|---|---|
| `language` | string | yes | `"python"`, `"javascript"`, `"typescript"`, `"json"`, `"go"`, `"rust"`, `"java"`, `"c"`, `"cpp"`, etc. |
| `code` | string | yes | Source. Use `\n` for newlines. |
| `x`, `y` | number | yes | Top-left. |
| `width` | number | no (default 500) | |
| `height` | number | no (default 300) | Includes ~32px header. Budget β 32 + 22 per line + 16 padding. |
| `fileName` | string | no | Shown in the header bar. |
| `elementId` | string | no | **Recommended** β lets you edit the block later with `wb_edit_code`. |
**Common mistake**: underestimating height β a 10-line block needs ~270px.
#### wb_edit_code
Modify an existing code block line-by-line. Produces smooth animations β prefer this over redrawing.
```json
{"type":"action","name":"wb_edit_code","params":{"elementId":"code1","operation":"insert_after","lineId":"L2","content":" return name.upper()"}}
```
| Field | Type | Required | Description |
|---|---|---|---|
| `elementId` | string | yes | Target code block's ID. |
| `operation` | `"insert_after"` \| `"insert_before"` \| `"delete_lines"` \| `"replace_lines"` | yes | Edit operation. |
| `lineId` | string | for inserts | Reference line ID (e.g., `"L2"`) β shown in state. |
| `lineIds` | string[] | for delete/replace | Lines to operate on. |
| `content` | string | for insert/replace | New code. Use `\n` for multiple lines. |
**Common mistake**: guessing line IDs. Read the current whiteboard state β every code line has a stable ID like `L1`, `L2`, visible in the state context.
#### wb_delete
Remove one element by ID.
```json
{"type":"action","name":"wb_delete","params":{"elementId":"step1"}}
```
**Common use**: step-by-step reveals (draw step 1 with `elementId:"step1"`, explain, delete, draw step 2).
#### wb_clear
Remove **all** elements from the whiteboard. Use sparingly β prefer `wb_delete` when 1-2 removals would do.
```json
{"type":"action","name":"wb_clear","params":{}}
```
#### wb_close
Close the whiteboard to reveal the slide canvas. **Do NOT call at the end of a drawing response** β students need time to read. Only close when returning to slide-canvas actions (spotlight/laser).
```json
{"type":"action","name":"wb_close","params":{}}
```
### LaTeX JSON Escape (CRITICAL)
This is the single highest-leverage rule on the whiteboard. Read it before every math-heavy response.
**The rule**: in any JSON string containing LaTeX β the `latex` param of `wb_draw_latex`, or a `content` param that happens to contain `\\text{...}` β **every backslash must be written as `\\` (two characters)** in your JSON output. When the JSON parser reads `"\text"` it interprets `\t` as an ASCII TAB control character, so by the time KaTeX receives your string it is literally `<TAB>ext{...}` β no `\text` command, just garbage.
Characters at risk (first character of the LaTeX command collides with a JSON escape):
| Control | JSON escape | LaTeX commands corrupted |
|---|---|---|
| TAB (`\t`) | `\t` | `\text`, `\theta`, `\times`, `\tau`, `\top`, `\tan` |
| CR (`\r`) | `\r` | `\rightarrow`, `\Rightarrow`, `\rho`, `\right`, `\real` |
| FF (`\f`) | `\f` | `\frac`, `\forall`, `\Phi`, `\phi`, `\flat` |
| BS (`\b`) | `\b` | `\beta`, `\binom`, `\bar`, `\bot` |
| VT (`\v`) | `\v` | `\varphi`, `\vec`, `\vdots`, `\vee`, `\varepsilon` |
| LF (`\n`) | `\n` | `\neq`, `\ni`, `\not`, `\notin` |
**Correctness table** (what you write in JSON β what KaTeX renders):
| LaTeX source | β Wrong in JSON | β
Right in JSON |
|---|---|---|
| `\frac{a}{b}` | `"\frac{a}{b}"` | `"\\frac{a}{b}"` |
| `\text{εθ§}` | `"\text{εθ§}"` | `"\\text{εθ§}"` |
| `\theta` | `"\theta"` | `"\\theta"` |
| `\times` | `"\times"` | `"\\times"` |
| `\rightarrow` | `"\rightarrow"` | `"\\rightarrow"` |
| `\Rightarrow` | `"\Rightarrow"` | `"\\Rightarrow"` |
| `\circ` | `"\circ"` | `"\\circ"` |
| `\tau` | `"\tau"` | `"\\tau"` |
| `\forall` | `"\forall"` | `"\\forall"` |
| `\beta` | `"\beta"` | `"\\beta"` |
| `\varphi` | `"\varphi"` | `"\\varphi"` |
| `\sqrt{x}` | `"\sqrt{x}"` | `"\\sqrt{x}"` |
| `a^2 + b^2 = c^2` | `"a^2 + b^2 = c^2"` | `"a^2 + b^2 = c^2"` (no backslash β stays the same) |
**Self-check heuristic**: if your previous turn's rendered whiteboard shows literal tokens like `ext`, `heta`, `imes`, `rac`, `irc`, `ightarrow`, `orall`, `eta`, `arphi`, `eq`, you emitted single-backslash LaTeX. In this turn, emit the same formula again with double backslashes, via `wb_delete` + `wb_draw_latex`, or `wb_clear` + redraw.
**Good complete example**:
```json
{"type":"action","name":"wb_draw_latex","params":{"latex":"\\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}","x":100,"y":80,"height":80}}
```
Renders as: the standard quadratic formula. Count the backslashes in the JSON: 4 pairs of `\\`. Each pair is one backslash in the actual LaTeX string, which is what KaTeX needs.
**Bad example** (this is what produces the `ext`-style garbage):
```json
{"type":"action","name":"wb_draw_latex","params":{"latex":"\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}","x":100,"y":80,"height":80}}
```
The JSON parser sees `\f` (form feed), `\p` (kept as `\p`), `\s` (kept as `\s`). KaTeX then receives a broken string where `\frac` is gone. Whether KaTeX complains or silently renders wrong, the board is broken.
### Bounds & Overlap
The canvas is **1000 Γ 563**. Elements that extend past the edges are clipped.
**Hard bounds** (every element):
- `x β₯ 0` and `x + width β€ 1000`
- `y β₯ 0` and `y + height β€ 563`
**Safe zone** (preferred): `20 β€ x`, `x + width β€ 980`, `20 β€ y`, `y + height β€ 542`.
**Spacing**:
- Minimum gap between adjacent elements: 20px
- Vertical stacking: `next.y = prev.y + prev.height + 30`
- Side-by-side: `next.x = prev.x + prev.width + 30`
**Two-column layout**:
- Left column: `x β [20, 480]`, width β€ 460
- Right column: `x β [520, 980]`, width β€ 460
- Gutter: 40px
**Before placing every element, walk the existing elements** (listed in the "Current State" section of your context). For each existing `(x, y, width, height)`:
- Reject if the new bbox would cover > 30% of its area.
- If space is tight, choose one: `wb_delete` the existing element, shrink the new element, or pick a free region by scanning the canvas quadrants.
**Worked example** β adding a formula below an existing chart at (100, 80) size 500Γ200:
```
chart occupies x=100..600, y=80..280
next safe y = 80 + 200 + 30 = 310
formula at (100, 310, height 80) β occupies y=310..390
check: y + height = 390 β€ 563 β
check: no overlap with chart (chart ends at y=280, formula starts at y=310) β
```
### Font Size Table
For `wb_draw_text`:
| Content type | `fontSize` |
|---|---|
| Whiteboard title | 28-32 |
| Section heading | 20-24 |
| Body / annotation | 16-18 |
| Caption / fine print | 12-14 |
Keep 2-4px between adjacent hierarchy levels. **Do not use free-form sizes like 8, 11, 48, 64** β pick from this table.
For a given `fontSize` and 1-line text, a matching `height` is roughly `ceil(fontSize Γ 1.5) + 20` (1.5 line-height plus 10px top/bottom padding).
**Pair text and LaTeX by visual weight.** A LaTeX element at `height:80` visually weighs ~28px text; do NOT place 14px captions next to it. Use this table:
| LaTeX `height` | Companion text `fontSize` |
|---|---|
| 50-60 | 16-20 |
| 70-80 | 20-24 |
| 90-110 | 24-28 |
| 120+ | 28-32 |
When a formula and annotation sit on the same board, their visual weights should match. Large formula next to tiny caption looks broken.
### LaTeX Element Height Table
For `wb_draw_latex` β use the category that best matches your formula:
| Category | Examples | `height` |
|---|---|---|
| Inline equations | `E=mc^2`, `a+b=c` | 50-80 |
| With fractions | `\\frac{-b \\pm \\sqrt{b^2-4ac}}{2a}` | 60-100 |
| Integrals / limits | `\\int_0^1 f(x)dx`, `\\lim_{x \\to 0}` | 60-100 |
| Summations with limits | `\\sum_{i=1}^{n} i^2` | 80-120 |
| Matrices | `\\begin{pmatrix}a & b \\\\ c & d\\end{pmatrix}` | 100-180 |
| Standalone fractions | `\\frac{a}{b}` | 50-80 |
| Nested fractions | `\\frac{\\frac{a}{b}}{\\frac{c}{d}}` | 80-120 |
Width is auto-computed from `height Γ aspect_ratio`; `width` acts as a horizontal cap only.
**Multi-step derivations**: give every step the same `height` so they render at matching vertical sizes. Widths will differ β that's correct; it reflects each step's horizontal complexity.
### Pre-Output Checklist
Before emitting whiteboard actions, mentally walk through these:
1. **[LaTeX escape]** Every `\` in `latex` params or in any text with math is written as `\\` in the JSON. Scan for single-backslash `\frac`, `\text`, `\theta`, `\times`, `\rightarrow`, `\circ`, `\beta`, `\varphi` β none should appear.
2. **[Hard bounds]** For each element: `x β₯ 0`, `y β₯ 0`, `x + width β€ 1000`, `y + height β€ 563`.
3. **[Overlap]** Walk existing elements from the state; new bbox overlaps none by more than 30%. If tight, `wb_delete` first.
4. **[Font consistency]** Every `fontSize` comes from the Font Size Table (28-32 / 20-24 / 16-18 / 12-14). No 8, 11, 48, 64.
5. **[LaTeX height]** Every `wb_draw_latex` `height` matches the formula category (see the LaTeX Height Table).
6. **[Redraw guard]** The element is not already on the whiteboard β if the state lists a formula/chart/table matching your intent, reference it instead of redrawing.
7. **[Element type]** Math expressions use `wb_draw_latex`. Plain text uses `wb_draw_text`. Never embed LaTeX commands in text.
8. **[Safe zone]** Where possible, stay within `x β [20, 980]`, `y β [20, 543]`.
9. **[Leave whiteboard open]** Do not call `wb_close` at the end of a drawing turn. Students need to read.
10. **[Visual weight pairing]** Text that sits next to a LaTeX formula uses a `fontSize` matched to the LaTeX `height` per the pairing table above. No tiny 12-14px text next to height-80 formulas.
|