mdeck 3.7.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +4 -4
  3. package/assets/base.css +9 -5
  4. package/assets/extensions/themes/academic/styles.css +22 -22
  5. package/assets/extensions/themes/glass/styles.css +17 -17
  6. package/assets/extensions/themes/minimal/styles.css +14 -14
  7. package/assets/extensions/themes/neue/styles.css +14 -14
  8. package/assets/extensions/themes/plain/styles.css +17 -17
  9. package/assets/extensions/themes/work/styles.css +26 -26
  10. package/docs/reference/authoring.md +12 -0
  11. package/docs/site/content/drawing.md +6 -2
  12. package/docs/site/content/media.md +3 -1
  13. package/docs/site/content/presenting.md +47 -0
  14. package/examples/python/slides.de.md +493 -0
  15. package/examples/python/{slides.md → slides.en.md} +1 -1
  16. package/examples/python/slides.fa.md +492 -0
  17. package/examples/python/slides.hi.md +492 -0
  18. package/examples/showcase/slides.md +33 -0
  19. package/package.json +1 -1
  20. package/skills/write-slides/SKILL.md +1 -0
  21. package/src/build/config.js +1 -1
  22. package/src/build/slidesPlugin.js +34 -4
  23. package/src/components/VideoPlayer.jsx +70 -6
  24. package/src/components/callout.css +10 -10
  25. package/src/components/citation.css +2 -2
  26. package/src/components/code-block.css +3 -3
  27. package/src/components/poll.css +6 -6
  28. package/src/components/video-player.css +15 -0
  29. package/src/core/editDeck.js +3 -2
  30. package/src/core/icons.js +1 -0
  31. package/src/core/labels.js +2 -0
  32. package/src/core/languages.js +51 -0
  33. package/src/core/parseSlides.js +15 -3
  34. package/src/core/validateDeck.js +5 -0
  35. package/src/editor/components/DeckSettings.jsx +4 -0
  36. package/src/editor/components/MetaFields.jsx +7 -0
  37. package/src/layouts/layoutApi.jsx +7 -1
  38. package/src/live/answer/answer.css +2 -2
  39. package/src/runtime/chrome.jsx +6 -7
  40. package/src/runtime/deck-stage.js +249 -11
  41. package/src/runtime/hotspots.js +98 -0
  42. package/src/runtime/ink/bus.js +21 -1
  43. package/src/runtime/ink/room.js +20 -8
  44. package/src/runtime/main.jsx +179 -23
  45. package/src/runtime/zoom/camera.js +77 -0
  46. /package/examples/python/{slides.drawings.json → slides.en.drawings.json} +0 -0
@@ -27,7 +27,7 @@
27
27
  .slide-logo {
28
28
  position: absolute;
29
29
  top: var(--pad-y);
30
- left: var(--pad-x);
30
+ inset-inline-start: var(--pad-x);
31
31
  height: 48px;
32
32
  width: auto;
33
33
  max-width: 280px;
@@ -153,25 +153,25 @@ strong { font-weight: 600; color: var(--ink); }
153
153
  grid-row: 1 / span 40;
154
154
  align-self: center;
155
155
  margin: 0;
156
- padding-right: 24px;
156
+ padding-inline-end: 24px;
157
157
  }
158
158
  .slide-body > :last-child { margin-bottom: 0; }
159
159
 
160
160
  /* ─────────────────────────────────────────────
161
161
  LISTS — a short title with a line under it; plain lines otherwise
162
162
  ───────────────────────────────────────────── */
163
- .slide-body ul > li { line-height: 1.45; padding-left: 34px; }
163
+ .slide-body ul > li { line-height: 1.45; padding-inline-start: 34px; }
164
164
  .slide-body ul > li::before {
165
165
  content: '\2013';
166
166
  position: absolute;
167
- left: 0;
167
+ inset-inline-start: 0;
168
168
  top: 0;
169
169
  color: var(--muted);
170
170
  }
171
171
  /* An item that starts in bold: the bold part is a title on its own line,
172
172
  the rest a smaller description under it, and no marker. */
173
173
  .slide-body ul > li:has(> strong:first-child) {
174
- padding-left: 0;
174
+ padding-inline-start: 0;
175
175
  font-size: calc(var(--fs-body) * 0.86);
176
176
  line-height: 1.45;
177
177
  color: var(--ink-soft);
@@ -184,11 +184,11 @@ strong { font-weight: 600; color: var(--ink); }
184
184
  color: var(--ink);
185
185
  margin-bottom: 4px;
186
186
  }
187
- .slide-body ol > li { line-height: 1.45; padding-left: 46px; }
187
+ .slide-body ol > li { line-height: 1.45; padding-inline-start: 46px; }
188
188
  .slide-body ol > li::before {
189
189
  content: counter(slide-ol) '.';
190
190
  position: absolute;
191
- left: 0;
191
+ inset-inline-start: 0;
192
192
  top: 0;
193
193
  font-variant-numeric: tabular-nums;
194
194
  color: var(--accent);
@@ -309,10 +309,10 @@ strong { font-weight: 600; color: var(--ink); }
309
309
  column-gap: 96px;
310
310
  align-content: center;
311
311
  align-items: start;
312
- text-align: left;
312
+ text-align: start;
313
313
  }
314
314
  .slide--focus .slide-body:has(> .focus-eyebrow) > * { grid-column: 2; }
315
- .slide--focus .slide-body:has(> .focus-eyebrow) > .focus-eyebrow { grid-column: 1; grid-row: 1 / span 2; align-self: center; padding-right: 24px; }
315
+ .slide--focus .slide-body:has(> .focus-eyebrow) > .focus-eyebrow { grid-column: 1; grid-row: 1 / span 2; align-self: center; padding-inline-end: 24px; }
316
316
  .slide--focus .slide-body:has(> .focus-eyebrow) .focus-content { align-items: flex-start; }
317
317
  .slide--focus .slide-body:has(> .focus-eyebrow) :is(.focus-statement, .focus-content h1, .focus-content p) {
318
318
  font-family: var(--font-body);
@@ -321,7 +321,7 @@ strong { font-weight: 600; color: var(--ink); }
321
321
  line-height: 1.4;
322
322
  letter-spacing: -0.005em;
323
323
  max-width: 900px;
324
- text-align: left;
324
+ text-align: start;
325
325
  }
326
326
 
327
327
  /* ─────────────────────────────────────────────
@@ -368,7 +368,7 @@ strong { font-weight: 600; color: var(--ink); }
368
368
  column-gap: 80px;
369
369
  align-items: center;
370
370
  }
371
- .slide--split .split-heading { margin: 0; padding-right: 24px; }
371
+ .slide--split .split-heading { margin: 0; padding-inline-end: 24px; }
372
372
  .slide--split .split-heading h1 { margin: 0; }
373
373
  .slide--split .slide-body:has(> .split-heading) .split-columns { align-self: stretch; }
374
374
 
@@ -402,7 +402,7 @@ strong { font-weight: 600; color: var(--ink); }
402
402
  .slide-body .callout {
403
403
  background: var(--surface);
404
404
  border: 0;
405
- border-left: 3px solid var(--accent);
405
+ border-inline-start: 3px solid var(--accent);
406
406
  border-radius: 0 8px 8px 0;
407
407
  padding: 20px 28px 22px;
408
408
  margin: 0 0 16px;
@@ -416,9 +416,9 @@ strong { font-weight: 600; color: var(--ink); }
416
416
  color: var(--ink);
417
417
  margin: 0 0 4px 0;
418
418
  }
419
- .slide-body .callout p { padding-left: 0; margin: 0; color: var(--ink-soft); }
419
+ .slide-body .callout p { padding-inline-start: 0; margin: 0; color: var(--ink-soft); }
420
420
  .slide-body .callout :is(.callout-title) { color: var(--ink); }
421
- .slide-body .callout:is(.callout-warning, .callout-caution) { border-left-color: var(--accent-3); }
421
+ .slide-body .callout:is(.callout-warning, .callout-caution) { border-inline-start-color: var(--accent-3); }
422
422
  .slide-body .callout.callout-proof { background: none; border: 0; padding: 0; }
423
423
 
424
424
  /* ─────────────────────────────────────────────
@@ -444,7 +444,7 @@ strong { font-weight: 600; color: var(--ink); }
444
444
  .slide-body .code-block-wrapper { margin: 0 0 var(--gap-item); }
445
445
 
446
446
  .slide-body table { font-size: calc(var(--fs-body) * 0.9); font-variant-numeric: tabular-nums; }
447
- .slide-body :is(th, td) { padding: 12px 24px 12px 0; }
447
+ .slide-body :is(th, td) { padding-block: 12px; padding-inline: 0 24px; }
448
448
  .slide-body th { font-weight: 600; color: var(--ink); border-bottom: 1px solid var(--ink); }
449
449
  .slide-body td { border-bottom: 1px solid var(--rule); }
450
450
 
@@ -464,7 +464,7 @@ strong { font-weight: 600; color: var(--ink); }
464
464
  FOOTNOTES, MATH, AUDIENCE QUESTIONS
465
465
  ───────────────────────────────────────────── */
466
466
  .slide-footnotes, .slide-citations { font-family: var(--font-body); }
467
- .slide .katex-display { font-size: var(--fs-sub); margin: 24px 0; overflow-x: auto; overflow-y: hidden; text-align: left; }
467
+ .slide .katex-display { font-size: var(--fs-sub); margin: 24px 0; overflow-x: auto; overflow-y: hidden; text-align: start; }
468
468
  .slide .poll-track, .slide .scale-track { border-radius: 4px; background: var(--surface); }
469
469
  .slide .poll-fill, .slide .scale-fill { border-radius: 4px; background: var(--accent); }
470
- .slide .question-cards li { border-radius: 8px; border-left: 0; background: var(--surface); }
470
+ .slide .question-cards li { border-radius: 8px; border-inline-start: 0; background: var(--surface); }
@@ -15,8 +15,8 @@
15
15
  content: '';
16
16
  position: absolute;
17
17
  top: 0;
18
- left: 0;
19
- right: 0;
18
+ inset-inline-start: 0;
19
+ inset-inline-end: 0;
20
20
  height: var(--band);
21
21
  background: var(--accent);
22
22
  z-index: 3;
@@ -47,7 +47,7 @@
47
47
  .slide-logo {
48
48
  position: absolute;
49
49
  top: var(--pad-y);
50
- left: var(--pad-x);
50
+ inset-inline-start: var(--pad-x);
51
51
  height: 72px;
52
52
  width: auto;
53
53
  max-width: 360px;
@@ -181,29 +181,29 @@ strong { font-weight: 600; color: var(--ink); }
181
181
  /* ─────────────────────────────────────────────
182
182
  LISTS — square bullets, numbers in the accent
183
183
  ───────────────────────────────────────────── */
184
- .slide-body ul > li { line-height: 1.4; padding-left: 40px; }
184
+ .slide-body ul > li { line-height: 1.4; padding-inline-start: 40px; }
185
185
  .slide-body ul > li::before {
186
186
  content: '';
187
187
  position: absolute;
188
- left: 2px;
188
+ inset-inline-start: 2px;
189
189
  top: calc(0.7em - 6px);
190
190
  width: 12px;
191
191
  height: 12px;
192
192
  background: var(--accent);
193
193
  }
194
194
  /* A point inside a point: a dash. */
195
- .slide-body li ul > li { padding-left: 34px; }
195
+ .slide-body li ul > li { padding-inline-start: 34px; }
196
196
  .slide-body li ul > li::before {
197
197
  top: calc(0.7em - 1.5px);
198
198
  width: 16px;
199
199
  height: 3px;
200
200
  background: var(--muted);
201
201
  }
202
- .slide-body ol > li { line-height: 1.4; padding-left: 52px; }
202
+ .slide-body ol > li { line-height: 1.4; padding-inline-start: 52px; }
203
203
  .slide-body ol > li::before {
204
204
  content: counter(slide-ol) '.';
205
205
  position: absolute;
206
- left: 0;
206
+ inset-inline-start: 0;
207
207
  top: 0;
208
208
  font-weight: 600;
209
209
  font-variant-numeric: tabular-nums;
@@ -238,7 +238,7 @@ strong { font-weight: 600; color: var(--ink); }
238
238
  .slide--title.has-image .title-image {
239
239
  position: absolute;
240
240
  top: 0;
241
- right: 0;
241
+ inset-inline-end: 0;
242
242
  bottom: 0;
243
243
  width: 40%;
244
244
  height: 100%;
@@ -248,7 +248,7 @@ strong { font-weight: 600; color: var(--ink); }
248
248
  }
249
249
  .slide--title.has-image .slide-header > span:last-child:not(.brand) { visibility: hidden; }
250
250
  /* The footer's hairline stops short of the picture (40% of 1920px, and a gap). */
251
- :is(.slide--title, .slide--chapter).has-image .slide-footer { margin-right: 712px; }
251
+ :is(.slide--title, .slide--chapter).has-image .slide-footer { margin-inline-end: 712px; }
252
252
 
253
253
  /* ─────────────────────────────────────────────
254
254
  LAYOUT: CHAPTER — a section divider: the number in the accent, a broader band
@@ -262,7 +262,7 @@ strong { font-weight: 600; color: var(--ink); }
262
262
  letter-spacing: -0.04em;
263
263
  font-variant-numeric: tabular-nums;
264
264
  color: var(--accent);
265
- margin: 0 0 40px -6px;
265
+ margin-block: 0 40px; margin-inline: -6px 0;
266
266
  }
267
267
  .chapter-meta {
268
268
  font-family: var(--font-body);
@@ -298,7 +298,7 @@ strong { font-weight: 600; color: var(--ink); }
298
298
  .slide--chapter.has-image .chapter-image {
299
299
  position: absolute;
300
300
  top: 0;
301
- right: 0;
301
+ inset-inline-end: 0;
302
302
  bottom: 0;
303
303
  width: 40%;
304
304
  height: 100%;
@@ -319,14 +319,14 @@ strong { font-weight: 600; color: var(--ink); }
319
319
  letter-spacing: 0.1em;
320
320
  text-transform: uppercase;
321
321
  color: var(--accent);
322
- margin: 0 0 32px 58px;
322
+ margin-block: 0 32px; margin-inline: 58px 0;
323
323
  }
324
324
  .focus-content {
325
325
  display: flex;
326
326
  flex-direction: column;
327
327
  align-items: flex-start;
328
- border-left: 10px solid var(--accent);
329
- padding: 6px 0 10px 48px;
328
+ border-inline-start: 10px solid var(--accent);
329
+ padding-block: 6px 10px; padding-inline: 48px 0;
330
330
  }
331
331
  .focus-statement,
332
332
  .slide--focus .focus-content h1,
@@ -345,7 +345,7 @@ strong { font-weight: 600; color: var(--ink); }
345
345
  font-family: var(--font-body);
346
346
  font-size: var(--fs-body);
347
347
  color: var(--muted);
348
- margin: 32px 0 0 58px;
348
+ margin-block: 32px 0; margin-inline: 58px 0;
349
349
  }
350
350
 
351
351
  /* ─────────────────────────────────────────────
@@ -386,8 +386,8 @@ strong { font-weight: 600; color: var(--ink); }
386
386
  ───────────────────────────────────────────── */
387
387
  .split-columns { gap: 0; }
388
388
  .slide--split :is(.split-left, .split-right) { padding: 0 56px; }
389
- .slide--split .split-left { padding-left: 0; border-right: 1px solid var(--rule); }
390
- .slide--split .split-right { padding-right: 0; }
389
+ .slide--split .split-left { padding-inline-start: 0; border-inline-end: 1px solid var(--rule); }
390
+ .slide--split .split-right { padding-inline-end: 0; }
391
391
 
392
392
  /* ─────────────────────────────────────────────
393
393
  LAYOUT: FULL-BLEED IMAGE — the title on a label at the lower left
@@ -407,8 +407,8 @@ strong { font-weight: 600; color: var(--ink); }
407
407
  letter-spacing: -0.015em;
408
408
  color: var(--ink);
409
409
  background: var(--bg);
410
- border-left: 10px solid var(--accent);
411
- padding: 28px 44px 32px 40px;
410
+ border-inline-start: 10px solid var(--accent);
411
+ padding-block: 28px 32px; padding-inline: 40px 44px;
412
412
  margin: 0;
413
413
  max-width: 1300px;
414
414
  text-wrap: balance;
@@ -433,7 +433,7 @@ strong { font-weight: 600; color: var(--ink); }
433
433
  --bar: var(--accent);
434
434
  background: var(--surface);
435
435
  border: 0;
436
- border-left: 8px solid var(--bar);
436
+ border-inline-start: 8px solid var(--bar);
437
437
  border-radius: 0 4px 4px 0;
438
438
  padding: 22px 32px 24px;
439
439
  margin: 14px 0 0;
@@ -447,7 +447,7 @@ strong { font-weight: 600; color: var(--ink); }
447
447
  text-transform: uppercase;
448
448
  margin: 0 0 8px 0;
449
449
  }
450
- .slide-body .callout p { padding-left: 0; margin: 0; color: var(--ink); }
450
+ .slide-body .callout p { padding-inline-start: 0; margin: 0; color: var(--ink); }
451
451
  .slide-body :is(.callout-note, .callout-tip, .callout-important) { --bar: var(--accent); }
452
452
  .slide-body :is(.callout-warning, .callout-caution) { --bar: var(--accent-3); }
453
453
  .slide-body .callout-definition { --bar: var(--accent-2); }
@@ -479,7 +479,7 @@ strong { font-weight: 600; color: var(--ink); }
479
479
  .slide-body blockquote {
480
480
  position: relative;
481
481
  margin: 0 0 var(--gap-item);
482
- padding: 0 0 0 64px;
482
+ padding-block: 0; padding-inline: 64px 0;
483
483
  border: 0;
484
484
  max-width: 1300px;
485
485
  font-size: calc(var(--fs-body) * 1.1);
@@ -490,7 +490,7 @@ strong { font-weight: 600; color: var(--ink); }
490
490
  .slide-body blockquote::before {
491
491
  content: '\201C';
492
492
  position: absolute;
493
- left: 0;
493
+ inset-inline-start: 0;
494
494
  top: -0.12em;
495
495
  font-family: var(--font-display);
496
496
  font-size: 104px;
@@ -503,7 +503,7 @@ strong { font-weight: 600; color: var(--ink); }
503
503
  FOOTNOTES, MATH, AUDIENCE QUESTIONS
504
504
  ───────────────────────────────────────────── */
505
505
  .slide-footnotes, .slide-citations { font-family: var(--font-body); }
506
- .slide .katex-display { font-size: var(--fs-sub); margin: 32px 0; overflow-x: auto; overflow-y: hidden; text-align: left; }
506
+ .slide .katex-display { font-size: var(--fs-sub); margin: 32px 0; overflow-x: auto; overflow-y: hidden; text-align: start; }
507
507
  .slide .poll-track, .slide .scale-track { border-radius: 2px; background: var(--surface); }
508
508
  .slide .poll-fill, .slide .scale-fill { border-radius: 2px; background: var(--accent); }
509
- .slide .question-cards li { border-radius: 4px; border-left: 6px solid var(--accent); background: var(--surface); }
509
+ .slide .question-cards li { border-radius: 4px; border-inline-start: 6px solid var(--accent); background: var(--surface); }
@@ -67,6 +67,7 @@ Each `---` line starts a new slide. Frontmatter is only needed when you want a s
67
67
  | `csl` | `apa` | Citation style: `apa`, `vancouver`, `harvard1`, or a `.csl` file |
68
68
  | `nocite` | — | References to list without citing them; `['*']` lists the whole file |
69
69
  | `show.citations` | `true` | `false` leaves out each slide's own references above the footer |
70
+ | `hotspots` | `off` | Number keys zoom in on parts of a slide while presenting: `auto` (pictures, code, tables, formulas, videos, callouts, columns, polls and `data-hotspot` elements), `marked` (only `data-hotspot` elements) or `off` (1–9 go to slides) |
70
71
 
71
72
  ### Theme params
72
73
 
@@ -162,6 +163,7 @@ description: A short description shown under the title.
162
163
  | `layout` | Slide layout (see below) |
163
164
  | `section` | Section label shown in the slide header (auto-propagated — see below) |
164
165
  | `title` | Name in the outline and reader navigation, for slides without a heading (not shown on the slide) |
166
+ | `hotspots` | This slide's own hotspots: `auto`, `marked`, `off` or `false` (see the deck field) |
165
167
 
166
168
  ### Section labels
167
169
 
@@ -537,6 +539,16 @@ A title written after the type on the `:::` line still wins over both.
537
539
 
538
540
  The presenter view, the launch page and the editor are tools for the author and always stay English.
539
541
 
542
+ ### One talk in several languages
543
+
544
+ Write the talk once per language, in files named for it, side by side: `talk.en.md`, `talk.de.md`, `talk.hi.md` and so on. The language is a two-letter code after the name, with a region if needed (`talk.de-CH.md`). A file named this way needs no `lang`: its name gives it.
545
+
546
+ `mdeck run talk.en.md` finds the other files with the same name and adds a **Language** switch to the presenter view (**L** goes to the next language). Switching changes the slides, your notes and mdeck's own words in every window: the audience window, a paired iPad and the phones following the talk. Your place stays, as do the step on the slide, the drawings and the poll results: slides match by their place in the deck, so keep the same slides in the same order in every language. A deck in one language shows no switch.
547
+
548
+ A language written from right to left, such as Farsi (`fa`), Arabic or Hebrew, sets its slides and your notes from right to left: the text, lists, quotations, tables and the place of the header and the page number. Code and maths stay left to right, as do mdeck's own controls.
549
+
550
+ Each file is a complete deck: `mdeck check`, `mdeck edit` and `mdeck send` work on one language at a time, and drawings and results are kept beside the file you run.
551
+
540
552
  To change single words, name them under `labels`:
541
553
 
542
554
  ```yaml
@@ -14,7 +14,7 @@ Press **D** in standalone slides or in the presenter view, or use the pen button
14
14
  | Laser pointer | A red dot with a white core and a short trail that disappears by itself, for pointing at something. With a pencil that can hover, the dot follows it without touching. Never kept. |
15
15
  | Eraser | Removes whole strokes you touch. |
16
16
 
17
- **Zoom**: two fingers zoom into the slide and move around it, one finger moves a zoomed slide, and Ctrl + scroll (a trackpad pinch) zooms on a laptop. Only the slide grows; the bars and the toolbar keep their size. The audience window shows the same part of the slide. **1:1** at the top left shows the whole slide again, as does the next slide.
17
+ **Zoom**: two fingers zoom into the slide and move around it, one finger moves a zoomed slide, and Ctrl + scroll (a trackpad pinch) zooms on a laptop. Only the slide grows; the bars and the toolbar keep their size. The audience window shows the same part of the slide. **1:1** at the top left shows the whole slide again, as does the next slide. To zoom straight to a picture or a table with a number key, see [hotspots](presenting.html#zoom-in-on-part-of-a-slide).
18
18
 
19
19
  On a touch screen such as an iPad, drawing is on as soon as the presenter view opens, and in the deck as soon as the pencil touches it, with the toolbar folded into its button in the bottom right corner (↘ folds it again). Until then, a tap on the right third of the screen goes forward, on the left third back, and a swipe does the same. Drawing starts with the laser pointer; choose the pen or the highlighter to write. The pen and the highlighter each have colours and three sizes, and each keeps its own; one pen colour is **Accent**, the accent colour of the theme and palette: a drawing in it changes with them. The other pen colours follow light and dark: on dark slides red, blue and green are lighter, and the text colour is white instead of black. The toolbar also has undo and redo (also Cmd/Ctrl+Z and Cmd/Ctrl+Shift+Z), **Clear this slide**, and **×** to stop drawing; **D** and **Escape** do the same. While you draw, the pencil and the mouse draw; fingers keep working: a swipe to the left goes forward, to the right back, a tap on a stroke selects it, and buttons and polls on the slide still respond. Turn slides with the arrow keys or the presenter view's arrows, as always. Holding the pen still for half a second at the end of a stroke makes it a straight line; near a multiple of 15° (horizontal, vertical, 45° …) it snaps to that angle.
20
20
 
@@ -48,7 +48,11 @@ There are two ways.
48
48
 
49
49
  1. Start `mdeck run my-talk.md --network`, so the iPad in the same network can reach your laptop.
50
50
  2. On the launch page, under **Present from an iPad**, choose **Show pairing code** and scan it with the iPad's camera. The presenter view opens on the iPad, paired with your laptop, so it may save drawings and steer the phones of a poll. It is the same presenter view as on the laptop; pairing only gives it these rights. Once it is open, the launch page says so.
51
- 3. On the laptop, open the **audience window** from the same place and move it to the projector. It follows the iPad: slides, revealed points, and drawings as you draw them. Navigation in the audience window also updates the iPad's slide, notes and next-slide preview.
51
+ 3. On the laptop, open the **audience window** from the same place and move it to the projector. It follows the iPad: slides, revealed points, drawings as you draw them, and videos. Navigation in the audience window also updates the iPad's slide, notes and next-slide preview.
52
+
53
+ **Videos.** A video file on a slide (`<videoplayer src="…" />`) plays, pauses and jumps on the projector as you tap it on the iPad. The sound comes from the projector: while the audience window is open, the iPad's copy plays silently. Browsers start sound only on a page someone has clicked, so click the audience window once before the talk (going full screen counts); otherwise the video plays there without sound and shows **Click for sound**.
54
+
55
+ Online videos (`<videoplayer url="…" />` from YouTube, Vimeo or SwitchTube) do not follow the iPad. They run inside the video service's own player, which mdeck cannot start or stop, so they play only on the screen where you start them. For a talk from the iPad, start them in the audience window on the laptop, or download the video and use a video file.
52
56
 
53
57
  A pairing code works once, for ten minutes. **Unpair** on the launch page ends every pairing; so does stopping `mdeck run`. Scan a new code afterwards.
54
58
 
@@ -86,6 +86,8 @@ To start a video when its slide appears, add `play="auto"`:
86
86
 
87
87
  Automatic playback is muted. Leaving the slide stops the local video; automatic videos also return to the beginning.
88
88
 
89
+ Presenting from an iPad paired with your laptop? Play, pause or jump in the video on the iPad, and the audience window on the projector does the same, with the sound; see [Present from an iPad](drawing.html#present-from-an-ipad).
90
+
89
91
  ## Show an online video
90
92
 
91
93
  Use `url` instead of `src` for a YouTube, Vimeo, or SwitchTube address:
@@ -94,7 +96,7 @@ Use `url` instead of `src` for a YouTube, Vimeo, or SwitchTube address:
94
96
  <videoplayer url="https://www.youtube.com/watch?v=YOUR_VIDEO_ID" />
95
97
  ```
96
98
 
97
- Replace the example address with your video's address. Online videos need an internet connection and permission from the video service to appear in another page. Test them before your talk.
99
+ Replace the example address with your video's address. Online videos need an internet connection and permission from the video service to appear in another page. Test them before your talk. They play only where you start them: a paired iPad cannot start one on the projector, as it can a video file.
98
100
 
99
101
  ## If a picture does not appear
100
102
 
@@ -40,6 +40,8 @@ Use its audience-window button to open a separate view of the slides. If you hav
40
40
 
41
41
  The two windows follow the same slide and reveal position: navigate in either window and the other follows. This works between windows in the same browser and between your laptop and a paired iPad. To connect the iPad, see [Draw on your slides](drawing.html#present-from-an-ipad).
42
42
 
43
+ A video file you play, pause or move in the presenter view does the same in the audience window, which plays the sound; the presenter view's copy stays silent while the audience window is open. Click the audience window once before the talk, so the browser lets it play sound.
44
+
43
45
  Small icons next to **Speaker View** show what is connected to the deck: presenter views, audience windows and, for decks with polls, how many phones. Point at them to see on which devices, such as "Presenter view on an iPad". The launch page shows the same under **Present**, and marks each view that is open.
44
46
 
45
47
  For a single screen, switch the presenter view to its slide-only layout. **F** or the fullscreen button fills the screen in either the presenter view or the audience window; fullscreen does not select another view.
@@ -59,11 +61,56 @@ To let people answer a question on their phones, put a poll on a slide. See [Ask
59
61
  | I | Hide or show the drawings |
60
62
  | F | Full screen, where the browser allows it |
61
63
  | N | Open or close the notes drawer, in the presenter view's slide-only layout |
64
+ | L | Switch to the talk's next language, for a talk written in several (see below) |
65
+ | 1–9 | Zoom in on a part of the slide, with hotspots on (see below); without them, go to slide 1–9 |
66
+ | 0 or Escape | Show the whole slide again |
67
+ | H | Turn hotspots on or off for this talk, in the presenter view |
62
68
 
63
69
  Click the slide area if your keys are not controlling it. Keys behave normally while you are typing in a text field.
64
70
 
65
71
  The timer is for your own reference; you can start, pause, and reset it in the presenter view.
66
72
 
73
+ ## Zoom in on part of a slide
74
+
75
+ Hotspots let you show one part of a slide large: a picture, a chart, a code block, a table. Turn them on in the deck's settings:
76
+
77
+ ```markdown
78
+ ---
79
+ hotspots: auto
80
+ ---
81
+ ```
82
+
83
+ The presenter view then puts a small numbered key on each part of the slide you can zoom to. Press its number, or tap the key on an iPad, and the slide zooms smoothly until that part fills the screen. A part of another shape than the screen keeps the slide around it in view. The audience window, a paired iPad and phones following the talk zoom along; only the presenter view shows the keys.
84
+
85
+ To see the whole slide again, press the same number again, **0** or **Escape**, tap the slide, or use **1:1**. The next point or the next slide shows the whole slide by itself, so you never need an extra key press to move on. Another number while zoomed goes straight to that part.
86
+
87
+ | Setting | What gets a key |
88
+ |---|---|
89
+ | `hotspots: auto` | Pictures, code blocks, tables, formulas, videos, callouts, columns and polls, and anything marked `data-hotspot` |
90
+ | `hotspots: marked` | Only what you marked with `data-hotspot`; nothing is found by itself |
91
+ | `hotspots: off` | Nothing. This is the default: 1–9 go to slides 1–9 |
92
+
93
+ A slide can have its own setting in its frontmatter, such as `hotspots: false` for a slide whose numbers you do not want, or `hotspots: auto` on one slide of a deck without hotspots. Mark a part of your own in inline HTML with `data-hotspot`, and keep a found one out with `data-hotspot="off"`:
94
+
95
+ ```markdown
96
+ The rate is <span data-hotspot>**2.4 %** a year</span>, for now.
97
+ ```
98
+
99
+ Parts that nearly fill the slide, or its whole width, get no key, since there is nothing to zoom; what is inside them may. A part inside another one shares its key: a column with a formula and a tip in it is one part. The keys follow reading order, up to nine on a slide. In the editor, the deck's settings and each slide's details have a **Hotspots** choice too. **H**, or the button beside **Draw**, turns hotspots on or off for the rest of the talk without changing the deck; a slide set to `false` stays without them.
100
+
101
+ ## One talk in several languages
102
+
103
+ To give a talk in English, German or another language as the room needs, write it once per language, in files side by side named for it:
104
+
105
+ ```text
106
+ talk.en.md
107
+ talk.de.md
108
+ ```
109
+
110
+ Start either with `mdeck run talk.en.md`: the presenter view gets a **Language** switch, and **L** goes to the next language. Switching changes the slides, your notes and the words mdeck shows in every window, including the audience window, a paired iPad and phones following along, and keeps your place, the step on the slide and the drawings. Slides match by their place in the deck, so keep the same slides in the same order in every file. A talk in one language shows no switch.
111
+
112
+ `mdeck send talk.de.md` makes the German file to hand out; each file is a complete deck of its own.
113
+
67
114
  ## Reveal points one at a time
68
115
 
69
116
  Wrap a list in a steps block: