Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ The rendered files are attached to the [latest release](../../releases/latest);
|---|---|---|
| 0–4 s | All of 26 U.S.C. § 24 (2,686 words) pours in under "…if the laws be so voluminous that they cannot be read…" (Federalist No. 62, 1788); the camera dives to "$2,200" in § 24(h)(2) | `data/statute.json` — uscode.house.gov (current through 2026-09-18), cross-checked word for word against Cornell LII; Avalon Project for Federalist No. 62; 1788 from Founders Online |
| 4–8.5 s | "$2,200" flies into lines 7–26 of `policyengine_us/parameters/gov/irs/credits/ctc/amount/base.yaml`; the § 24(h)(2) chip docks on the line that cites it; "What if Congress raised the credit to $3,000?" with the reform dict exactly as passed to policyengine.py | `data/base.yaml` at the policyengine-us commit in `data/base.yaml.commit`; `data/household.json → meta.reform_dict_passed` |
| 8.5–14 s | "Take a married couple in Ohio," kids 4 and 8, one earner: the change in net income drawn across earnings from $0 to $120,000. "$0 below $42,200 in earnings. +$1,600 from $58,000." "The refundable part stays at $1,700 per child, so the extra $1,600 only offsets income tax the current credit leaves unpaid." | `data/earnings_sweep.json` (policyengine_us axes, one point per $250; cross-checked with policyengine.py at 7 earnings levels) |
| 14–20 s | Zoom out to all 50 states and DC: 12,000 weighted draws of households, each placed at random in its assigned congressional district; gainers light up grouped by gain (about $800, $1,600, then $2,400 and more); federal cost, share gaining, children out of poverty | `data/national.json`, `data/households_sample.json`, district shapes from `data/district_geography.json` |
| 20–25 s | The same dots settle on the baseline of each income decile; bars show average change per household | `data/national.json` → `deciles.by_decile` (full sample, not the 12,000 draws) |
| 25–30 s | The dots form the wordmark; tagline; provenance lines | — |
| 8.5–14 s | "Take a married couple in Ohio," kids 4 and 8, one earner: the change in net income drawn across earnings from $0 to $120,000. "$0 below $42,200 in earnings. +$1,600 from $58,000." "The refundable part stays at $1,700 per child, so the extra $1,600 only offsets income tax the current credit leaves unpaid." Source tag: "policyengine.py 6.1.1 · static" | `data/earnings_sweep.json` (policyengine_us axes, one point per $250), reproduced by policyengine.py's household calculator at all 601 points to $0.004 (`data/compute/checks/curve_policyengine_py.json`) |
| 14–20 s | Zoom out to all 50 states and DC: 12,000 weighted draws of households, each placed at random in its assigned congressional district; gainers light up grouped by gain (about $800, $1,600, then $2,400 and more); federal cost, share gaining, children out of poverty. Source tag: "policyengine.py 6.1.1 · populace_us_2024 · static / poverty: Supplemental Poverty Measure". The 12,000 draws cover 6,976 distinct households | `data/national.json`, `data/households_sample.json`, district shapes from `data/district_geography.json` |
| 20–25 s | The same dots settle on the baseline of each income decile; bars show average change per household. Source tag: "policyengine.py 6.1.1 · populace_us_2024 · static" | `data/national.json` → `deciles.by_decile` (full sample, not the 12,000 draws) |
| 25–30 s | The dots form the wordmark; tagline; "Free and open source · policyengine.org" | — |

Each chart carries its own small print in its bottom-right corner (`data/video.json → sources`, built from the versions and dataset each run recorded), so the close stays clean.

## The reform

Expand Down Expand Up @@ -72,7 +74,7 @@ These hold for every input, and `bun run test` plus CI check them (`tests/`, `.g

- `site/` — a deterministic HTML/canvas timeline. `window.renderAt(t)` draws the frame at time `t`; nothing depends on wall-clock time or `Math.random`.
- `tools/render.mjs` — Playwright drives headless Chromium frame by frame. `--stream out.mp4` pipes PNG screenshots straight into parallel ffmpeg encoders and joins the segments, so no frames touch the disk.
- `tools/soundtrack.py` — the score is synthesized with numpy/scipy at 120 BPM (D minor; Bb → C → F under the wordmark), mastered to −14 LUFS integrated with a 4× oversampled true-peak limiter at −2 dBTP. Sound effects come from `events.json`, which the page exports from the same timeline, so each click, bell and plink lands on the frame that causes it; gainer plinks rise in pitch with the $800 step.
- `tools/soundtrack.py` — the score is synthesized with numpy/scipy at 120 BPM (D minor; Bb → C → F under the wordmark), mastered to −14 LUFS integrated with a 4× oversampled true-peak limiter at −2 dBTP. Sound effects come from `events.json`, which the page exports from the same timeline, so each click and soft mallet note lands on the frame that causes it; gainer notes rise in pitch with the $800 step, and the family curve brightens a held chord as the gain rises.
- `tools/determinism.mjs` — proves a fresh page and a page that played the film up to *t* render identical pixels at 11 timestamps, in both layouts. Streaming workers start mid-film, so this is what makes parallel rendering safe.
- `tools/adapt_outputs.py` → `tools/build_video_data.py` — turn the raw PolicyEngine outputs into `data/video.json`, the only data the page reads. If any input is missing the page paints a striped MOCK DATA banner on every frame.

Expand Down
2 changes: 1 addition & 1 deletion audio/events.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"t":0,"type":"pour","dur":1.4},{"t":0.2,"type":"word","i":0},{"t":0.3,"type":"word","i":1},{"t":0.4,"type":"word","i":2},{"t":0.5,"type":"word","i":3},{"t":0.6,"type":"word","i":4},{"t":0.7,"type":"word","i":5},{"t":0.8,"type":"word","i":6},{"t":0.9,"type":"word","i":7},{"t":1,"type":"word","i":8},{"t":1.1,"type":"word","i":9},{"t":1.2,"type":"word","i":10},{"t":2.75,"type":"whoosh","dur":0.75},{"t":3.5,"type":"lock"},{"t":4,"type":"whoosh","dur":0.8499999999999996},{"t":4.25,"type":"key","i":0},{"t":4.282,"type":"key","i":1},{"t":4.314,"type":"key","i":2},{"t":4.346,"type":"key","i":3},{"t":4.378,"type":"key","i":4},{"t":4.41,"type":"key","i":5},{"t":4.442,"type":"key","i":6},{"t":4.474,"type":"key","i":7},{"t":4.506,"type":"key","i":8},{"t":4.538,"type":"key","i":9},{"t":4.57,"type":"key","i":10},{"t":4.602,"type":"key","i":11},{"t":4.634,"type":"key","i":12},{"t":4.666,"type":"key","i":13},{"t":4.698,"type":"key","i":14},{"t":4.73,"type":"key","i":15},{"t":4.762,"type":"key","i":16},{"t":4.794,"type":"key","i":17},{"t":4.826,"type":"key","i":18},{"t":4.85,"type":"land"},{"t":4.858,"type":"key","i":19},{"t":5.3,"type":"ping","note":0},{"t":6.85,"type":"key","i":40},{"t":6.91,"type":"key","i":41},{"t":6.97,"type":"key","i":42},{"t":7.03,"type":"key","i":43},{"t":7.09,"type":"key","i":44},{"t":7.25,"type":"ping","note":4},{"t":9.1,"type":"curve","samples":[[9.1,0],[9.145,0],[9.19,0],[9.235,0],[9.28,0],[9.325,0],[9.37,0],[9.415,0],[9.46,0],[9.505,0],[9.55,0],[9.595,0],[9.64,0],[9.685,0],[9.73,0],[9.775,0],[9.82,0],[9.865,380],[9.91,830],[9.955,1305],[10,1600],[10.045,1600],[10.09,1600],[10.135,1600],[10.18,1600],[10.225,1600],[10.27,1600],[10.315,1600],[10.36,1600],[10.405,1600],[10.45,1600],[10.495,1600],[10.54,1600],[10.585,1600],[10.63,1600],[10.675,1600],[10.72,1600],[10.765,1600],[10.81,1600],[10.855,1600],[10.9,1600]],"gmax":1600},{"t":10.65,"type":"rise","dur":0.7999999999999989},{"t":11,"type":"ping","note":0},{"t":11.5,"type":"hit"},{"t":14,"type":"drop"},{"t":14.88,"type":"plink","n":44,"step":1},{"t":14.94,"type":"plink","n":216,"step":1},{"t":15,"type":"plink","n":232,"step":1},{"t":15.06,"type":"plink","n":208,"step":1},{"t":15.12,"type":"plink","n":213,"step":1},{"t":15.18,"type":"plink","n":199,"step":1},{"t":15.24,"type":"plink","n":125,"step":1},{"t":15.42,"type":"plink","n":103,"step":2},{"t":15.48,"type":"plink","n":146,"step":2},{"t":15.54,"type":"plink","n":123,"step":2},{"t":15.6,"type":"plink","n":140,"step":2},{"t":15.66,"type":"plink","n":146,"step":2},{"t":15.72,"type":"plink","n":112,"step":2},{"t":15.78,"type":"plink","n":15,"step":2},{"t":15.9,"type":"plink","n":12,"step":3},{"t":15.96,"type":"plink","n":52,"step":3},{"t":16.02,"type":"plink","n":58,"step":3},{"t":16.08,"type":"plink","n":58,"step":3},{"t":16.14,"type":"plink","n":51,"step":3},{"t":16.2,"type":"plink","n":67,"step":3},{"t":16.26,"type":"plink","n":28,"step":3},{"t":16.5,"type":"stat","i":0},{"t":17,"type":"stat","i":1},{"t":17.5,"type":"stat","i":2},{"t":20,"type":"whoosh","dur":0.9},{"t":21,"type":"decile","n":3,"v":0.013392857142857142},{"t":21.07,"type":"decile","n":4,"v":0.16294642857142858},{"t":21.14,"type":"decile","n":5,"v":0.2924107142857143},{"t":21.21,"type":"decile","n":6,"v":0.5223214285714286},{"t":21.28,"type":"decile","n":7,"v":0.7366071428571429},{"t":21.35,"type":"decile","n":8,"v":0.8415178571428571},{"t":21.42,"type":"decile","n":9,"v":1},{"t":21.49,"type":"decile","n":10,"v":0.8973214285714286},{"t":21.56,"type":"decile","n":11,"v":0.9598214285714286},{"t":21.63,"type":"decile","n":12,"v":0.5736607142857143},{"t":25,"type":"swell","dur":1},{"t":26,"type":"logo"}]
[{"t":0,"type":"pour","dur":1.4},{"t":0.2,"type":"word","i":0},{"t":0.3,"type":"word","i":1},{"t":0.4,"type":"word","i":2},{"t":0.5,"type":"word","i":3},{"t":0.6,"type":"word","i":4},{"t":0.7,"type":"word","i":5},{"t":0.8,"type":"word","i":6},{"t":0.9,"type":"word","i":7},{"t":1,"type":"word","i":8},{"t":1.1,"type":"word","i":9},{"t":1.2,"type":"word","i":10},{"t":2.75,"type":"whoosh","dur":0.75},{"t":3.5,"type":"lock"},{"t":4,"type":"whoosh","dur":0.8499999999999996},{"t":4.25,"type":"key","i":0},{"t":4.282,"type":"key","i":1},{"t":4.314,"type":"key","i":2},{"t":4.346,"type":"key","i":3},{"t":4.378,"type":"key","i":4},{"t":4.41,"type":"key","i":5},{"t":4.442,"type":"key","i":6},{"t":4.474,"type":"key","i":7},{"t":4.506,"type":"key","i":8},{"t":4.538,"type":"key","i":9},{"t":4.57,"type":"key","i":10},{"t":4.602,"type":"key","i":11},{"t":4.634,"type":"key","i":12},{"t":4.666,"type":"key","i":13},{"t":4.698,"type":"key","i":14},{"t":4.73,"type":"key","i":15},{"t":4.762,"type":"key","i":16},{"t":4.794,"type":"key","i":17},{"t":4.826,"type":"key","i":18},{"t":4.85,"type":"land"},{"t":4.858,"type":"key","i":19},{"t":5.3,"type":"ping","note":0},{"t":6.85,"type":"key","i":40},{"t":6.91,"type":"key","i":41},{"t":6.97,"type":"key","i":42},{"t":7.03,"type":"key","i":43},{"t":7.09,"type":"key","i":44},{"t":7.25,"type":"ping","note":4},{"t":9.1,"type":"curve","samples":[[9.1,0],[9.145,0],[9.19,0],[9.235,0],[9.28,0],[9.325,0],[9.37,0],[9.415,0],[9.46,0],[9.505,0],[9.55,0],[9.595,0],[9.64,0],[9.685,0],[9.73,0],[9.775,0],[9.82,0],[9.865,380],[9.91,830],[9.955,1305],[10,1600],[10.045,1600],[10.09,1600],[10.135,1600],[10.18,1600],[10.225,1600],[10.27,1600],[10.315,1600],[10.36,1600],[10.405,1600],[10.45,1600],[10.495,1600],[10.54,1600],[10.585,1600],[10.63,1600],[10.675,1600],[10.72,1600],[10.765,1600],[10.81,1600],[10.855,1600],[10.9,1600]],"gmax":1600},{"t":11,"type":"ping","note":0},{"t":11,"type":"rise","dur":0.9499999999999993},{"t":12,"type":"hit"},{"t":14,"type":"drop"},{"t":14.88,"type":"plink","n":44,"step":1},{"t":14.94,"type":"plink","n":216,"step":1},{"t":15,"type":"plink","n":232,"step":1},{"t":15.06,"type":"plink","n":208,"step":1},{"t":15.12,"type":"plink","n":213,"step":1},{"t":15.18,"type":"plink","n":199,"step":1},{"t":15.24,"type":"plink","n":125,"step":1},{"t":15.42,"type":"plink","n":103,"step":2},{"t":15.48,"type":"plink","n":146,"step":2},{"t":15.54,"type":"plink","n":123,"step":2},{"t":15.6,"type":"plink","n":140,"step":2},{"t":15.66,"type":"plink","n":146,"step":2},{"t":15.72,"type":"plink","n":112,"step":2},{"t":15.78,"type":"plink","n":15,"step":2},{"t":15.9,"type":"plink","n":12,"step":3},{"t":15.96,"type":"plink","n":52,"step":3},{"t":16.02,"type":"plink","n":58,"step":3},{"t":16.08,"type":"plink","n":58,"step":3},{"t":16.14,"type":"plink","n":51,"step":3},{"t":16.2,"type":"plink","n":67,"step":3},{"t":16.26,"type":"plink","n":28,"step":3},{"t":16.5,"type":"stat","i":0},{"t":17,"type":"stat","i":1},{"t":17.5,"type":"stat","i":2},{"t":20,"type":"whoosh","dur":0.9},{"t":21,"type":"decile","n":3,"v":0.013392857142857142},{"t":21.07,"type":"decile","n":4,"v":0.16294642857142858},{"t":21.14,"type":"decile","n":5,"v":0.2924107142857143},{"t":21.21,"type":"decile","n":6,"v":0.5223214285714286},{"t":21.28,"type":"decile","n":7,"v":0.7366071428571429},{"t":21.35,"type":"decile","n":8,"v":0.8415178571428571},{"t":21.42,"type":"decile","n":9,"v":1},{"t":21.49,"type":"decile","n":10,"v":0.8973214285714286},{"t":21.56,"type":"decile","n":11,"v":0.9598214285714286},{"t":21.63,"type":"decile","n":12,"v":0.5736607142857143},{"t":25,"type":"swell","dur":1},{"t":26,"type":"logo"}]
40 changes: 40 additions & 0 deletions data/compute/checks/curve_policyengine_py.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"description": "policyengine.py pe.us.calculate_household with an earnings axis, at every point of earnings_sweep.json",
"points": 601,
"tolerance_dollars": 0.01,
"max_abs_diff_dollars": 0.00390625,
"versions": {
"policyengine": "6.1.1",
"policyengine-us": "2.2.1",
"policyengine-core": "3.32.5",
"spm-calculator": "1.0.0",
"microdf-python": "1.3.10",
"numpy": "2.5.3",
"pandas": "3.0.6",
"h5py": "3.16.0",
"tables": "3.11.1",
"python": "3.13.9",
"platform": "macOS-26.6.2-arm64-arm-64bit-Mach-O"
},
"sweep_versions": {
"policyengine": "6.1.1",
"policyengine-us": "2.2.1",
"policyengine-core": "3.32.5",
"spm-calculator": "1.0.0",
"microdf-python": "1.3.10",
"numpy": "2.5.3",
"pandas": "3.0.6",
"h5py": "3.16.0",
"tables": "3.11.1",
"python": "3.13.9",
"platform": "macOS-26.6.2-arm64-arm-64bit-Mach-O"
},
"runtime": {
"started_at_utc": "2026-09-27T19:26:35.112205+00:00",
"finished_at_utc": "2026-09-27T19:32:32.527723+00:00",
"wall_clock_seconds": 357.41,
"laps_seconds": {
"calculate_household": 357.35
}
}
}
65 changes: 65 additions & 0 deletions data/compute/curve_policyengine_py.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""The family curve through policyengine.py, at every plotted point.

earnings_sweep.py computes the curve with policyengine_us.Simulation axes and
spot-checks policyengine.py's household calculator at 7 earnings levels. The
video's tag on that chart names policyengine.py, so this runs the whole $250
grid (601 points, $0 to $150,000) through pe.us.calculate_household with an
earnings axis, baseline and reform, and asserts the change in net income
matches the sweep at every point.

Run: ../.venv/bin/python curve_policyengine_py.py (from this directory)
Writes: checks/curve_policyengine_py.json
"""

from __future__ import annotations

import json
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))

from common import DATA_DIR, YEAR, Timer, package_versions, write_json # noqa: E402

timer = Timer()
import policyengine as pe # noqa: E402

TOL = 0.01 # dollars

sweep = json.loads((DATA_DIR / "earnings_sweep.json").read_text())
meta = json.loads((DATA_DIR / "household.json").read_text())["meta"]
hd = meta["household_definition"]
E = sweep["earnings"]
assert E[0] == 0 and E[-1] == 150_000 and len(E) == 601

people = [dict(p) for p in hd["people"]]
assert people[0].get("is_tax_unit_head"), "the axis runs over person 0, which must be the earner"
people[0]["employment_income"] = 0
axes = [[{"name": "employment_income", "min": E[0], "max": E[-1], "count": len(E)}]]
kw = dict(people=people, tax_unit={"filing_status": hd["filing_status"]}, household={"state_code": hd["state_code"]},
year=meta["year"], spm={"geography_kind": "national"}, axes=axes)
assert meta["year"] == YEAR

net = {}
for label, reform in (("baseline", None), ("reform", meta["reform_dict_passed"])):
r = pe.us.calculate_household(**kw, reform=reform)
net[label] = [float(x) for x in r.household["household_net_income"]]
assert len(net[label]) == len(E), (label, len(net[label]))
timer.lap("calculate_household")

gain = [b - a for a, b in zip(net["baseline"], net["reform"])]
diff = [abs(g - s) for g, s in zip(gain, sweep["gain"])]
worst = max(diff)
assert worst < TOL, f"policyengine.py differs from the sweep by ${worst:.4f}"

out = {
"description": "policyengine.py pe.us.calculate_household with an earnings axis, at every point of earnings_sweep.json",
"points": len(E),
"tolerance_dollars": TOL,
"max_abs_diff_dollars": worst,
"versions": package_versions(),
"sweep_versions": sweep["meta"]["versions"],
"runtime": timer.summary(),
}
write_json(Path(__file__).resolve().parent / "checks" / "curve_policyengine_py.json", out)
print(json.dumps({k: v for k, v in out.items() if k != "versions"}, indent=1))
2 changes: 1 addition & 1 deletion data/video.json

Large diffs are not rendered by default.

Loading
Loading