Research talk decks

SkillDocs & knowledge

Author a Quarto reveal.js deck for a research talk: seminar, conference, job talk, brown bag. TRIGGER on "slides for my talk", "seminar deck", "job talk", "turn this paper into slides", "add an appendix slide", "export a handout". Classroom material is teaching-lecture; auditing an existing deck is slide-review.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Research talk decks skill

What this skill tells your AI

The instructions your AI receives, as published by ericluo04/claude-academic-workflow in skills/research-talk/SKILL.md and read by ahel’s review.

Build a deck a seminar audience can follow cold: a clear visual hierarchy in which the exhibit dominates each slide, and staged reveals only where they help a point land.

Builds a .qmd that renders to a reveal.js HTML deck for a seminar, conference talk, job talk, or brown bag. The audience is other researchers who are reading dense exhibits and following an argument, so the deck stays quiet and the evidence carries the weight.

Out of scope: classroom lectures (use teaching-lecture, which has its own theme, a larger root font for a lecture hall, and the pedagogy vocabulary), auditing a deck you did not write (use slide-review), and LaTeX Beamer (use compile-latex).

Shared theme and tooling live in ~/.claude/assets/quarto-yale/. README.md there is the machinery reference: what the filter rewrites, what the gates assert, the reference packer, the progress-bar takeover, and the settings that silently break a deck. Read it for any of that; where it and the source disagree, the source wins. The head of starter-theme.scss carries the theme's own reasoning about each class.

Read next to this file

  • references/closing-slide.md: the thank-you slide, the QR slot, how the progress bar and the slide numbers end.
  • references/staging.md: fragments, beats, .r-stack layers, auto-animate, what a jump button costs.
  • references/figures-and-code.md: figure sizing, code display, two columns, tables, R setup.
  • references/citations.md: citing and the reference list.
  • style/house.md: the author's wording and calibration (closing-slide text, the author line, button labels, density anchors, dates).
  • assets/starter-template.qmd: copy it to start a deck; do not transcribe.
  • The README above: tool internals and jump-button mechanics.

Before drafting anything

Do not open the .qmd until these four are pinned down. Ask the user; do not guess, and do not infer them from the paper.

  1. Audience and venue. An NBER session, a marketing seminar, a psychology brown bag, and a CS lab meeting want different amounts of setup and different notation. Name the room.
  2. The one-sentence claim. If the audience remembers one thing, what is it? Write it down verbatim. It becomes the title slide, the claim slide, and the closing slide.
  3. Time slot, and whether it is protected. Fifteen minutes with interruptions is a different deck from fifty minutes uninterrupted.
  4. What is already built. Point at the paper, the .tex, existing figures, the R or Python that produces the exhibits. Rebuilding a figure from scratch when the script exists wastes the time budget.

Then write the title list before any slide bodies, and read it back to the user as a list. Fixing the argument at that stage costs one message; fixing it after twenty slides exist costs an hour.

Content doctrine

Titles are short labels of three to five words, and style/house.md is the calibration; read it before writing a title list. Labels ("Where we are", "Prompting confounds") put the claim in the body and the voiceover. The alternative is assertion titles ("Disclosure raises prices only where search costs are high"), which let a listener who tunes out for a minute rejoin by reading one line; offer them only when the deck is not your own, and ask which the deck wants. Either way: one or two lines, and if the title needs three, the point is not sharp yet.

The deck is one argument. A paper has four contributions and a talk has one. Pick the claim that can be defended in the slot and move the rest to the appendix. Deciding what the talk is not about is most of the work. One idea per slide; a slide with two jobs also tends to be the slide that overflows.

The house style is a narrated picture book, calibrated in style/house.md: phrases and not sentences, and the figure sized to the slide geometry. The slide carries the exhibit and the one line that names what it shows, and the speaker carries the argument. A sparse slide is finished, so do not fill it in with supporting sentences; err to the sparse side every time. Longer text is welcome when it arrives as one block of full sentences, staged so it lands as you say it; three sentences of prose land more easily than eight compressed bullets, and what ruins a slide is overwhelming the room, with word count only a proxy for that. The calibration numbers and their Beamer anchors are in style/house.md. A slide that asserts one clause in two to five words carries a turn in the argument on its own: ## {.center} holding ::: {.r-fit-text} scales the line to the slide width (the starter template has one).

What goes on the slide: the title, the exhibit, the focal number, and any formal statement whose exact wording has to be on the wall. What the speaker says: the setup, the intuition, the caveats, and the sentence that connects this slide to the one before it. A line that exists so the audience can follow along later belongs in ::: {.notes} or in the paper. Write speaker notes on every slide that carries a step in the argument; they are what make a sparse slide safe to present from. ::: {.notes} goes to reveal's speaker view (press S), written as the sentences you intend to say out loud, and appears in neither PDF export, so anything a handout reader needs stays in the slide body.

Every exhibit needs an interpretation next to it: the exhibit on the left, the reading on the right (two columns, in references/figures-and-code.md), and the focal number annotated in the exhibit itself so the point survives being read cold.

Ghost-deck check, run before writing bodies and again before the talk: read only the titles, in order; they should compose into the argument. A title that could sit anywhere in the sequence is either misplaced or unnecessary.

State the claim early. The audience decides in the first three minutes whether to engage or read email, so the claim gets its own slide by slide three, before methods. End on the conclusion slide, which carries the claim and the headline estimate, then the thank-you slide (references/closing-slide.md).

Build the appendix as you go: every cut for time and every anticipated question is an appendix slide. Mark them {.appendix} so they run on the muted scheme and you can spot them while scrolling under pressure, and open the run with an {.appendix-break} divider. A job talk wants ten to twenty of these.

Cite on the slide where the borrowed thing appears, in the small muted style the theme gives .aside-note and .citation; do not make the audience wait for a references slide to learn whose figure they are looking at. The full list still goes at the end, after the appendix (references/citations.md).

Never type a reference by hand: not into a slide, not into a tooltip, not into the .bib. Every author, year, journal, and title comes out of a verified .bib mechanically, because a citation typed from memory or reconstructed from a citekey gets fabricated, and the room often includes the people being cited. references/citations.md has the rule and the generator pattern; run the bibcheck skill on the .bib before the talk.

Deck architecture

A workable spine for empirical work: title, motivation (one or two), the claim, setting and data, identification or method, results (one finding per slide), mechanism or heterogeneity, the main threat and what answers it, conclusion, thank you, then appendix. Theory talks substitute setup, assumptions, main proposition, intuition for the proof, comparative statics.

A third spine, the framework arc, for a paper whose contribution is a method or framework, with the application there to demonstrate it: title, motivation, the claim, setting and data, then a framework overview slide whose exhibit is a roadmap (the whole pipeline in one schematic), then one numbered .section-break per pipeline stage (represent, discover, validate, redesign, or whatever the pipeline's verbs are). Each stage reopens on the same roadmap exhibit with the active stage highlighted and closes on its own deliverable; results live inside the stages, with no separate results act. After the last stage: the causal or external validation study, the main threat, conclusion, thank you. The recurring-roadmap mechanics are in references/staging.md.

A multi-study paper (observational plus experiment is the common marketing shape) gets one .section-break per study, each study running a mini arc inside its section: design, stimuli or data, specification, result, heterogeneity if any. The claim slide early and the conclusion slide aggregate across studies, and a confirmatory experiment is its own station, never filed under mechanism-or-heterogeneity. No new classes are needed.

Budget roughly one slide per minute of speaking, and leave the last slide up. Twenty-minute conference talk: fifteen to eighteen content slides. Ninety-minute job talk: forty to fifty, plus a deep appendix. Build the appendix past the budget on purpose.

Front matter, via the extension

The deck uses the starter-revealjs extension format. Adopt it once per deck directory:

cd <deck dir>
quarto add ~/.claude/assets/quarto-yale --no-prompt   # installs _extensions/starter/
cp -R ~/.claude/assets/quarto-yale/{mathjax,fonts} .
format: starter-revealjs
bibliography: talk-refs.bib   # only on a deck that cites

The format carries the whole verified recipe: the theme layered on default, stage-slide.lua, citeproc: false with refs-fit: starter, self-hosted MathJax 2.7.9 pinned to its own TeX webfonts, highlight-style: a11y, slide-number: c/t, date-format: long, incremental: true, fig-align: center, auto-animate-duration: 0.4, and echo/warning/message off. Its _extension.yml says why each line is there.

The mathjax/ copy is why math needs no CDN: the format points MathJax at the deck's own mathjax/MathJax.js, resolved by the browser relative to the rendered page. Writing html-math-method: mathjax as a bare string instead loads pandoc's MathJax 4 from jsDelivr at display time (README). MathJax is the engine because a formal talk needs what KaTeX cannot do: \eqref and \label, \DeclareMathOperator, mathtools, and physics.

stage-slide.lua does six jobs (staging, divider numbering, the progress and slide-number takeover, jump buttons, reference pagination, citation-tooltip retargeting; the README lists them), so keep the format even on a deck that wants no staging and use {.no-stage} per slide instead. slide-number: c/t out of the box counts every slide in the t, so a 19-slide argument with an appendix behind it would close at 19/26; the filter re-meters it so the main body runs 1/19 to 19/19 and the appendix and references share a tail run (references/closing-slide.md).

Unknown or misspelled YAML keys are ignored silently and the render still exits 0. When an option seems not to have taken, quarto inspect deck.qmd prints the resolved format as JSON.

Variant: one self-contained file

For a room where nothing can be counted on, build a single HTML file that opens from a thumb drive, an email attachment, or behind a hotel wifi captive portal, which is the case that ruins talks. Swap the math engine and embed everything:

format:
  starter-revealjs:
    embed-resources: true
    html-math-method: katex      # bare string, never the object form
    self-contained-math: true

The object form ({method: katex, url: ...}) leaves a runtime loader that embed-resources cannot inline, so the deck loses all its math the moment there is no network; KaTeX is the only engine Quarto embeds, and it has no \eqref, \label, or \DeclareMathOperator of its own, so numbered equations in this variant go through Quarto's @eq- cross-references, resolved before KaTeX sees the math (README, "The offline variant"). With the KaTeX fonts inlined a normal talk lands between 5 and 6 MB. check-offline.py is the gate for this variant, and only for this variant.

Math and macros

Define macros as bare raw LaTeX at the top level of the document, outside any math block, parked on a hidden ## Notation {visibility="hidden"} slide as the starter template does. They expand at parse time, so the same definitions work under MathJax and under the KaTeX variant. Wrapping them in $$ ... $$ fails: pandoc consumes them and every later use errors with "unexpected control sequence". A MathJax config header or a ```{=tex} block does not work either (README, "Math macros").

Numbered equations: tag the display block $$ ... $$ {#eq-main} and reference it with @eq-main. That form survives a rebuild as the self-contained variant; raw \label plus \eqref also works under MathJax and dies under KaTeX. mathtools and physics commands are available under MathJax.

Theme classes

From starter-theme.scss. Use Quarto div and span syntax.

ClassFor
.resultA framed estimate. Put [Estimate]{.label} on its own line first.
.takeawayThe slide's one claim, on a rule under the content. Once per slide at most.
.assumptionAn identification assumption or formal condition.
.theorem .proposition .lemmaFormal statements, with a [Proposition 1]{.label} span.
.proofGets an automatic QED square on its last element.
.appendixOn the slide heading: ## Robustness {.appendix}. Muted appendix scheme plus a standing APPENDIX label.
.thanks-slideThe closing slide of the main body. See references/closing-slide.md.
.section-breakNumbered section divider. Number, title, vertical middle.
.appendix-breakThe same divider with no number, muted. Goes before the first .appendix slide, with background-color="var(--appendix-ground)".
.references-breakThat divider again, at the very end, with background-color="var(--references-ground)".
.referencesOn the reference-list heading. The filter copies it onto every continuation page, so you write it once.
.aside-noteMuted caveat or scope condition. Arrives with the block above it.
.jumpA button to a named appendix slide, on its own line and outside any bordered block: [Sample Windows]{.jump target="ap-window"}.
.jump-backThe button back, to the exact slide and step the jump started from. Leave the span empty and it reads Back: []{.jump-back}.
.togetherOn a div, so everything inside it arrives on one keypress.
.with-previousOn a div, so it arrives on the beat of the block above it.
.no-stageOn a heading, so the slide arrives whole.
.specOn a wide specification table, so it shrinks instead of clipping.
.numRight-align a numeric table column.
.highlight-yaleA fragment variant that turns a term to the accent colour on cue (.highlight-accent is the alias).
.yblue .ymid .ygray .ygreen .yamber .yred .dimInline color spans.

Use the theorem environments wherever the talk has formal content. A proposition belongs in a box that says Proposition, carrying a [Proposition 1]{.label} span and the statement worded exactly as you want it read; the same goes for .assumption on an identification condition. A formal statement is one of the few things that earns full sentences on the wall, because the room has to be able to hold you to the wording. Quarto gives theorem divs zero styling in reveal.js, which is why the theme supplies it.

Dividers

Two archetypes, each a heading and nothing else, composed on the full canvas (on the starter theme, a display numeral over a short standing rule over the centred title), which is what makes them read as a turn in the talk:

## Setting and identification {.section-break}

## Appendix {.appendix-break background-color="var(--appendix-ground)"}

stage-slide.lua numbers the .section-break dividers, so never hand-number them: insert a section and the rest renumber on the next render. Copy the appendix attribute exactly as written; if it is missing the theme paints the same ground as a fallback, and the references divider takes var(--references-ground) the same way. Do not add background-color to a .section-break: a coloured field there is noise, and the class alone is the contract. Appendix content slides keep the page ground on purpose, marked by the muted scheme and the standing label instead. The print-view behaviour and the contrast classification are in the README.

Vertical alignment

Content slides are top-aligned, Quarto's center: false default. {.center} works per slide and is the fix for a sparse slide, which otherwise pools all its whitespace at the bottom and reads as half-finished: centre anything carrying one line, one number, or one assertion, e.g. ## The sign flips {.center}.

Staging in brief

Content arrives as you say it. The format's filter stages every top-level block on a content slide, so the slide opens as its title alone and the blocks arrive one keypress each; a note that annotates the block above it (.aside-note, .citation, .caption, .with-previous) rides that block's beat, .together makes a group one beat, and {.no-stage} turns staging off for one slide. Everything else, and the caveats, are in references/staging.md; the filter's internals are in the README.

Build and verify

The render exits 0 whether or not the deck is presentable, so the gates are not optional. Run them every time, and again before the talk.

Put the sequence in a build.sh next to the deck on day one, rather than running the commands by hand, with two entry points: ./build.sh renders the HTML and runs both gates, and ./build.sh full adds the self-contained variant, the offline gate, and the PDF. On a deck that also ships the self-contained variant, derive that variant's .qmd inside the script by injecting the three embed keys into the real source, so there is one source file and the standalone cannot drift from the deck being edited. Keeping two .qmd files in sync by hand fails silently: the deck renders, the gates pass, and the file uploaded to the conference is a week old.

Iterate on the HTML and leave the PDF for the end. The render is not the slow step: on a 26-slide deck carrying 129 images (62 MB), quarto render takes 2 seconds, the standalone render 5, both gates about 9, and the decktape PDF 49, because decktape drives a headless browser through every slide and every fragment and does not care how the HTML was made. So the everyday loop is edit, ./build.sh, open the HTML; ./build.sh full runs once when the slides are final, and once more after any late edit. A PDF built mid-iteration is stale the moment the next edit lands, and the minutes it costs are what make a deck feel slow to work on.

cd <deck dir>
quarto render deck.qmd 2>&1 | tee /tmp/render.log
grep '\[WARNING\]' /tmp/render.log            # unclosed divs warn here and still exit 0

node ~/.claude/assets/quarto-yale/deck-check.mjs fit deck.html   # must print DECK-FITS: YES
node ~/.claude/assets/quarto-yale/stage-check.mjs deck.html      # must print STEP-0-CLEAN: YES

# self-contained variant only; verdict line is the padded label OFFLINE-SAFE
~/.claude/assets/quarto-yale/check-offline.py deck.html

The fit gate exists because the reveal canvas is a fixed 1050x700 that reveal scales to the window: a slide overflowing by 345 px looks fine on a laptop and gets cut off on the projector, and there is no allowframebreaks to save it. The gate visits every slide with fragments forced visible and fails on overflow, excess width, missing images, crushed or shrunk figures, unrendered math, a dangling .jump target, and an unpaginated bibliography; it warns on a nearly empty slide (the stray macro block), and --json prints per-image geometry. On overflow, cut content or split the slide; do not shrink the font, since the 30 px root is already calibrated for a seminar room.

stage-check.mjs asserts that nothing but the heading is visible before each content slide is advanced, then walks the slide forward and fails any press that changes no visible ink (DEAD STEP, presses counted from 1). It costs about two seconds a deck; the sample talk measures zero dead steps. It skips the slides it classifies as archetypes and reports which, so a divider that has quietly become a content slide shows up. What each gate measures, and how, is in the README.

check-offline.py decodes percent-encoded data URIs before searching, which a plain grep for cdn.jsdelivr cannot do; the verdict lines are fetchable refs and external hosts, and a nonzero math count under KaTeX is the expected state. Run it only on the self-contained variant: a default build is not self-contained and fails it by design.

Looking at the slides

Read the pictures, not the markup. While iterating, export only the slide under edit; the full PDF is the end-of-build artefact above:

# one slide (about 20 s, most of it browser start-up and the deck load)
npx -y decktape@latest reveal --size 1050x700 --slides 20 "file://$PWD/deck.html" one.pdf
~/.claude/assets/bin/pdfread.py png one.pdf --pages 1 --dpi 110 --out /tmp/s   # /tmp/s-1.png
# then Read /tmp/s-1.png

# the whole deck, once the slides are final
npx -y decktape@latest reveal --size 1050x700 "file://$PWD/deck.html" deck.pdf

--slides takes 20, 1-3, or 1-3,5,8 (decktape's own help), and the one-slide PDF has one page, so --pages 1. On the full PDF, --pages takes 3, 1-5, or 1,4,9; pdfread.py text pulls the wording across many slides at once, and pdfread.py pages gives the count. Chrome's own --headless --print-to-pdf writes a blank PDF on a live deck, and the Read tool cannot open PDFs on this machine. Claude in Chrome opens a visible window at whatever size it has; prefer decktape or deck-check.mjs handout.

Handout

decktape (the command above) gives one page per slide with every fragment revealed, which is usually what a handout should be. For one page per build step, set pdf-separate-fragments: true in the front matter and print through reveal's print view (verified: a three-slide deck with three fragments came out as six pages):

node ~/.claude/assets/quarto-yale/deck-check.mjs handout deck.html deck-handout.pdf

pdf-separate-fragments defaults to false in Quarto, the opposite of reveal's own default, and decktape ignores it, since it drives the live deck through reveal's API. Hyperlinks do not survive PDF export: jump buttons print as small outlined labels that do nothing, which is right for a handout, but say so when you build them and keep the appendix reachable by slide number too.

Publishing

quarto publish gh-pages puts one document per repository, so a repo can host one talk; for several, use one repo each or publish to docs/ and manage the paths yourself (the README weighs the two routes). Build the self-contained variant whenever the room is uncertain.

Traps, all verified on this machine

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
23
Forks
3
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
research-talk
Source
github.com/ericluo04/claude-academic-workflow