Skip to content

Add a reproducible toolkit for the Preceptor Table → DGM → graph animation - #36

Open
sophiezla wants to merge 1 commit into
PPBDS:mainfrom
sophiezla:add-animation-toolkit
Open

Add a reproducible toolkit for the Preceptor Table → DGM → graph animation#36
sophiezla wants to merge 1 commit into
PPBDS:mainfrom
sophiezla:add-animation-toolkit

Conversation

@sophiezla

Copy link
Copy Markdown
Contributor

Adds animations/, a self-contained folder that teaches an AI agent how to build the narrated animation connecting a Preceptor Table, the DGM formula, and the final answer.

Nothing under book/ changes. git diff main -- book/ is empty. No chapter, no rendered output, no book asset is touched.

What the animation is

One continuous narrated video, not two clips. The table fills row by row, the filled values fly down and become a graph, and the table stays faintly visible under the finished histogram. That persistence is the argument: the graph did not replace the table, it is what the table becomes when you run it enough times. Cutting between two clips would destroy exactly that claim.

Two videos per chapter, not one

Every example chapter carries a primary question and its paired opposite framing, so one script builds both from a framing argument:

Predictive Paired causal
Table columns one Outcome column two potential-outcome columns
Flies to the graph the outcome their difference
Act 3 redraws one error both errors, independently
The payoff "the answer is a spread, not a number" "the effect is a spread, and it crosses zero"

In the causal cut, one potential outcome per row is greyed and italic — the branch that unit did not live. The fundamental problem of causal inference, sitting in a table cell.

The quantity being graphed funnels through a single value column, so no layer below the table knows which framing it is drawing. Forking the script to add a framing would guarantee the pair drifts apart, and drift between a chapter's primary and paired artefacts is the one thing it cannot afford.

Narration drives the edit

Each beat is held for exactly as long as its sentence takes to say, measured from the synthesised audio at build time. There is no beat-length constant to tune — to change the pace, change the words. The spoken line and the on-screen caption are the same sentence, so a muted viewer loses nothing, which matters because tutorials often play muted.

Contents

~50 KB of text, no binaries:

animations/
  animations.md                 design contract, requirements, build gotchas
  preceptor_to_graph_video.R    one script, four renders
  example-embed.qmd             worked example of the finished embed
  .gitignore                    excludes rendered video + narration cache
BUILD_ANIMATIONS=true Rscript animations/preceptor_to_graph_video.R

Requires gganimate, av, ggtext, tuneR, plus edge-tts for narration. No external ffmpeg. check_deps() fails early naming exactly what is missing, and narrate = FALSE builds silent videos when edge-tts is unavailable. Runs from any working directory.

On reproducibility — one honest caveat

The statistical content is deterministic: set.seed(2026) sits inside the builder, so every error draw and every table value is identical run to run.

The edit timing is not. Beats are cut to synthesised speech, and edge-tts is a network service that returns marginally different audio for the same sentence. A cold rebuild moved frame counts by up to 14 frames (0.7s) per video. This is documented in animations.md §10 so nobody treats a differing frame count as a bug. Committing the narration/ cache would make rebuilds byte-identical, at ~25 MB.

Verification

  • Cold build from an empty cache: exit 0, no errors or warnings, all four videos regenerated
  • Full quarto render of the book: exit 0, all 18 chapters
  • example-embed.qmd lives outside the Quarto project, so it can never render into the book by accident
  • All relative links resolve

Two things worth a reviewer's opinion

  1. The worked example is the Senators net-worth question from guide/tables.md §10.3, chosen as the simplest table in the guide. It is a demonstration, not any chapter's material. Adopting it for a real chapter means editing the two CONFIG blocks and the narration sentences, and nothing below them. Which chapter should claim it is an open question.

  2. The causal cut gives Y(1) and Y(0) independent error draws, so the individual causal effect is τ + (ε₁ − ε₀), spread by σ√2. Reusing one error makes every unit's effect exactly τ, the distribution collapses to a spike, and Act 3 has nothing to show. If the Primer would rather teach constant treatment effects, Act 3 needs a different subject.

Also in this PR, and separable if you would rather it were: CLAUDE.md's "Record corrections" protocol is generalised to say lessons belong in the most specific file that owns the subject, with the reasoning attached rather than just the rule.

🤖 Generated with Claude Code

…imation

Adds animations/, a self-contained folder that teaches an AI agent how to
build the narrated animation connecting a Preceptor Table, the DGM formula,
and the final answer. Nothing under book/ changes.

The animation is one continuous narrated video, not two clips: the table
fills row by row, the filled values fly down and become a graph, and the
table stays faintly visible under the finished histogram. That persistence
is the argument -- the graph did not replace the table, it is what the table
becomes when you run it enough times.

Two videos per chapter, not one. Every example chapter carries a primary
question and its paired opposite framing, so one script builds both from a
`framing` argument: the predictive cut fills a single Outcome column and
graphs the outcome; the causal cut fills two potential-outcome columns,
greys the one that can never be observed, and graphs their difference
against a zero line. The quantity being graphed funnels through a single
`value` column so no layer below the table knows which framing it is
drawing -- forking the script would guarantee the pair drifts apart.

Narration drives the edit. Each beat is held for exactly as long as its
sentence takes to say, measured from synthesised audio at build time, so
there is no beat-length constant to tune; to change the pace, change the
words. The spoken line and the on-screen caption are the same sentence, so
a muted viewer loses nothing.

Contents (~50 KB of text, no binaries):

  animations.md               design contract, requirements, and the
                              build gotchas worth not rediscovering
  preceptor_to_graph_video.R  one script, four renders
  example-embed.qmd           worked example of the finished embed
  .gitignore                  excludes the ~4 MB of rendered video and
                              the ~25 MB narration cache, both of which
                              are reproducible output

Build with:

  BUILD_ANIMATIONS=true Rscript animations/preceptor_to_graph_video.R

Requires gganimate, av, ggtext and tuneR, plus edge-tts for narration; no
external ffmpeg. check_deps() fails early naming exactly what is missing,
and narrate = FALSE builds silent videos when edge-tts is unavailable.

The worked example is the Senators net-worth question from guide/tables.md
10.3, chosen as the simplest table in the guide. It is a demonstration, not
any chapter's material; adopting it means editing the two CONFIG blocks and
the narration sentences, and nothing below them.

CLAUDE.md gains a pointer to the toolkit, and its "Record corrections"
protocol is generalised to say lessons belong in the most specific file
that owns the subject, with the reasoning attached.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant