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.