๐ฏ Quarto Revealjs Slide Optimization Skill
๐ฏ Quarto Revealjs Slide Optimization Skill
Purpose
This skill optimizes interactive Quarto Revealjs slides based on visual feedback (screenshots). It identifies empty space or overflow issues and applies systematic adjustments to achieve optimal fit.
๏ฟฝ User Preferences (CRITICAL)
Font Size Requirements
- Minimum font size: 30pt equivalent (for students in back rows)
- Always prioritize readability over fitting more content
- When in doubt, go LARGER
Content Strategy
- Split slides when content is dense rather than shrinking text
- One concept per slide is better than cramped content
- Use
{.smaller}class sparingly, only for interactive slides with controls
Revealjs Font Size Reference
| CSS em value | Approximate pt | Use Case | |โโโโโ|โโโโโ-|โโโ-| | 0.6em | ~24pt | โ Too small - avoid | | 0.75em | ~30pt | โ
Minimum acceptable | | 0.85em | ~34pt | โ
Good for dense slides | | 1.0em | ~40pt | โ
Preferred for text | | 1.2em | ~48pt | โ
Great for key points |
๏ฟฝ๐ธ Skill Trigger
When user provides a screenshot of a slide showing:
- โ Too much empty space at bottom/sides
- โ Content overflow or truncation
- โ Elements too small for visibility
- โ Poor proportions between text and visualizations
๐ง Optimization Parameters
Slide Dimensions Reference
- Standard Revealjs: 1280ร720 pixels
- Usable content area: ~1200ร620 (after margins/headers)
Container Font Sizes
| Layout Type | Optimal Font Size | Margin Top | |โโโโ-|โโโโโโ-|โโโโ| | Dense interactive | 0.72em - 0.75em | -5px to -10px | | Standard content | 0.8em - 0.85em | 0px | | Sparse content | 0.9em - 1em | 5px |
Column Width Ratios
| Layout | Left (Controls/Text) | Right (Plot) | |โโโ|โโโโโโโ|โโโโโ| | Single plot | 20-25% | 75-80% | | Dual plots | 20% | 40% / 40% | | Text-heavy | 32-35% | 65-68% |
Plot Dimensions (for 1280ร720 slides)
| Plot Type | Small | Medium | Large | Max | |โโโโ|โโ-|โโโ|โโ-|โโ| | Single 2D | 400ร400 | 500ร500 | 600ร600 | 720ร600 | | Single 3D | 420ร380 | 500ร450 | 580ร520 | 650ร580 | | Dual plots | 380ร380 | 460ร460 | 520ร520 | - | | Contour | 600ร400 | 720ร480 | 820ร520 | 900ร580 |
๐ Optimization Algorithm
Step 0: Check Content Density
IF too_many_words_on_slide (> 80 words):
โ SPLIT into multiple slides
โ Each slide = one concept
โ Never shrink text below 0.75em (30pt)
IF using {.smaller} class:
โ Only acceptable for interactive slides with controls
โ Never for pure text/content slides
Step 1: Analyze Screenshot
IF significant_empty_space_at_bottom:
โ Increase plot height by 15-25%
โ Increase container font-size by 0.05-0.1em
IF empty_space_on_sides:
โ Increase plot width by 10-20%
โ Adjust column ratios (give more to plot)
IF content_overflow_or_truncation:
โ Decrease plot dimensions by 10-15%
โ Reduce container font-size by 0.05em
โ Increase negative margin-top
IF elements_too_small:
โ Increase font-size in HTML templates
โ Increase dot/marker sizes (r: 5 โ 6)
โ Increase axis label font sizes
Step 2: Apply Adjustments
For Container Wrapper
:::::: {style="font-size: 0.75em; margin-top: -5px;"}
For Text Panels (HTML in OJS)
html`<div style="font-size: 1.1em; line-height: 1.4;">
<p style="font-size: 1.5em; color: #2563eb;">
<strong>Key Value</strong>
</p>
</div>`
For Observable Plot
Plot.plot({
width: 460,
height: 460,
marginLeft: 50,
marginBottom: 50,
// ... marks
})
For Plotly 3D
const layout = {
width: 480,
height: 460,
margin: {l: 0, r: 0, b: 0, t: 0},
scene: {
xaxis: {title: 'x', titlefont: {size: 14}},
yaxis: {title: 'y', titlefont: {size: 14}},
zaxis: {title: 'z', titlefont: {size: 12}},
camera: { eye: {x: 1.5, y: 1.5, z: 1.1} },
aspectmode: 'cube'
}
};
๐ฎ Smartboard Compatibility
Always add event propagation prevention to interactive elements:
viewof mySlider = {
const input = Inputs.range([0, 10], {value: 5, step: 0.1, label: "Parameter:"});
// Prevent slide navigation on touch/click
input.addEventListener('pointerdown', e => e.stopPropagation());
input.addEventListener('touchstart', e => e.stopPropagation());
input.addEventListener('mousedown', e => e.stopPropagation());
input.addEventListener('click', e => e.stopPropagation());
input.addEventListener('wheel', e => e.stopPropagation());
input.addEventListener('pointermove', e => e.stopPropagation());
input.addEventListener('touchmove', e => e.stopPropagation());
input.addEventListener('mousemove', e => e.stopPropagation());
return input;
}
For Plotly 3D containers:
// After creating the plot
const plotDiv = container.querySelector('.js-plotly-plot');
if (plotDiv) {
['pointerdown', 'touchstart', 'mousedown', 'click', 'wheel',
'pointermove', 'touchmove', 'mousemove'].forEach(eventType => {
plotDiv.addEventListener(eventType, e => e.stopPropagation());
});
}
๐ Quick Reference Templates
Two-Column: Controls + Single Large Plot
## ๐ฎ Interactive: [Title] {.smaller}
:::::: {style="font-size: 0.72em; margin-top: -8px;"}
::::: columns
::: {.column width="25%"}
```{ojs}
// Slider controls + text panel
:::
::: {.column width=โ75%โ}
// Large plot (width: 820, height: 520)
::: ::::: ::::::
### Three-Column: Controls + 2D + 3D Plots
```markdown
## ๐ฎ Interactive: [Title] {.smaller}
:::::: {style="font-size: 0.75em; margin-top: -5px;"}
::::: columns
::: {.column width="20%"}
```{ojs}
// Controls + text
:::
::: {.column width=โ40%โ}
// 2D plot (width: 460, height: 460)
:::
::: {.column width=โ40%โ}
// 3D plot (width: 480, height: 460)
::: ::::: ::::::
---
## โ
Validation Checklist
After optimization, verify:
- [ ] **Font size โฅ 30pt (0.75em)** - CRITICAL for back-row visibility
- [ ] No content cut off at bottom
- [ ] No horizontal scrollbar
- [ ] Text readable at presentation distance (test from 5+ meters)
- [ ] Interactive elements responsive
- [ ] Plots fill available space proportionally
- [ ] Consistent styling across similar slides
- [ ] If slide feels cramped โ SPLIT IT
---
## ๐ When to Split a Slide
**Split when:**
- More than 80 words on a slide
- More than 5 bullet points
- Need to use font < 0.75em to fit content
- Multiple distinct concepts
- Complex formula + explanation
**Split strategy:**
Slide A: Problem Statement + Setup Slide B: Solution Step 1 Slide C: Solution Step 2 + Conclusion
---
## ๐ Example Optimization Session
**User provides screenshot showing:** Empty space at bottom (~100px)
**Analysis:**
- Current plot: 380ร380
- Current font: 0.65em
- Available space: ~100px vertical
**Actions:**
1. Increase plot to 460ร460 (+80px)
2. Increase font to 0.75em
3. Adjust margins from -10px to -5px
4. Increase dot radius from 5 to 6
**Result:** Optimal fit with improved visibility
---
*Last updated: February 2, 2026*
*Based on: multivariate_lecture1.qmd interactive slides*
---
## ๐ค Autopilot Compile-Check-Fix Workflow
**When user asks for autopilot optimization:**
CYCLE 1: Compilation Check
- COMPILE: quarto render โfile.qmdโ 2>&1
- CHECK: Analyze output for errors/warnings
- FIX: Apply fixes based on error type
- REPEAT: Until clean compilation
CYCLE 2: Font Size Audit (Code Analysis)
- SCAN: grep for font-size < 30px or em < 0.75
- SCAN: grep for {.smaller} class usage
- FIX: Increase fonts to minimum 30px/0.75em
- SPLIT: If slide too dense, split into multiple
CYCLE 3: Visual Check (if user provides screenshots)
- ANALYZE: Empty space โ increase fonts
- ANALYZE: Overflow โ split slide or reduce slightly
- FIX: Apply adjustments
- RECOMPILE: Verify changes ```
Grep Patterns for Font Audit
# Find fonts below 30px
grep -E "font-size:\s*(2[0-9]|1[0-9])px" file.qmd
# Find fonts below 0.75em
grep -E "font-size:\s*0\.[56]" file.qmd
# Find .smaller class usage
grep "{.smaller}" file.qmd
Common Quarto Errors & Fixes
| Error | Fix | |โโ-|โโ| | no package called 'X' | install.packages('X') | | object not found | Check variable scope in R chunks | | unexpected token | Check OJS syntax, missing brackets | | duplicate attribute | Merge width into style attribute | | weight= typo | Change to width= | | Overfull content | Split slide or reduce font by 2-4px | | Empty space | Increase font by 4-10px |
๐ป R Code Visibility for Students
Best practice for teaching slides:
#| echo: true # Show code
#| code-fold: true # Collapsed by default
#| code-summary: "๐ Show Code" # Button label
#| message: false
#| warning: false
Folding Options
| Option | Behavior | |โโโ|โโโ-| | code-fold: true | Collapsed by default (click to expand) | | code-fold: show | Expanded by default (click to collapse) | | code-fold: false | Always visible, no toggle |
๐ Callout Box Font Sizing
For callout boxes with explicit font-size:
| Content Density | Font Size | Use Case |
|---|---|---|
| Sparse (4 items) | 42-45px | Practice problems, summaries |
| Medium (6-8 items) | 36-38px | Definitions, theorems |
| Dense (10+ items) | 32-34px | Detailed examples |
Rule: If bottom 1/3 of slide is empty โ increase font by 8-10px
โฑ๏ธ Countdown Timer for Activities
Package: countdown (R package)
Installation
install.packages('countdown')
Basic Usage (Think-Pair-Share, Group Work, etc.)
#| echo: false
library(countdown)
countdown(minutes = 4, seconds = 0,
top = 0, right = 0, # Position: top-right corner
font_size = "1.5em",
color_running_background = "#31b09e", # Green while running
color_running_text = "white",
color_finished_background = "#cc3311", # Red when done
color_finished_text = "white",
color_warning_background = "#f7dc6f", # Yellow warning
warn_when = 60, # Warn at 60 seconds left
play_sound = TRUE) # ๐ Alarm when finished
Position Options
| Position | Code | |โโโ-|โโ| | Top-right | top = 0, right = 0 | | Top-left | top = 0, left = 0 | | Bottom-right | bottom = 0, right = 0 | | Bottom-left | bottom = 0, left = 0 | | Centered below content | top = "60%", left = "40%" |
Timer Interaction
- Click to start/pause
- Double-click to reset
- Alarm sound plays when timer reaches 0
Activity Duration Guidelines
| Activity Type | Duration | Timer Setting | |โโโโโ|โโโ-|โโโโโ| | Quick Think | 1 min | minutes = 1 | | Think-Pair-Share | 4 min | minutes = 4 | | Group Problem | 5-8 min | minutes = 5 or minutes = 8 | | Case Study | 10-15 min | minutes = 10 or minutes = 15 |
