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
4 changes: 2 additions & 2 deletions lib/slideshows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ import { overhang2026LightningConfig } from "@/slideshows/overhang-2026-lightnin
import { blsTaxsim2026Config } from "@/slideshows/bls-taxsim-2026/config";
import { scottishGovernment2026Config } from "@/slideshows/scottish-government-2026/config";
import { goodGrowthFoundation2026Config } from "@/slideshows/good-growth-foundation-2026/config";
import { introduction2026Config } from "@/slideshows/introduction-2026/config";
import { autumnBudget2026Config } from "@/slideshows/autumn-budget-2026/config";

export const slideshows: SlideshowConfig[] = [
introduction2026Config,
autumnBudget2026Config,
goodGrowthFoundation2026Config,
scottishGovernment2026Config,
blsTaxsim2026Config,
Expand Down
10 changes: 10 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ const nextConfig: NextConfig = {
env: {
NEXT_PUBLIC_BASE_PATH: '/slides',
},
// The Autumn Budget 2026 webinar deck was introduction-2026 until 28 October.
async redirects() {
return [
{
source: '/introduction-2026/:path*',
destination: '/autumn-budget-2026/:path*',
permanent: true,
},
];
},
// Pin the workspace root so Turbopack does not silently pick up a stray
// lockfile from a parent directory during local development or CI.
turbopack: {
Expand Down
1 change: 1 addition & 0 deletions public/logos/funders/nuffield-foundation-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# Analysing the UK Autumn Budget 2026 with PolicyEngine
# Analysing the Autumn Budget 2026 with PolicyEngine

5 slides at `/slides/introduction-2026`, for the 28 October 2026 webinar:
5 slides at `/slides/autumn-budget-2026`, for the 28 October 2026 webinar
(`/slides/introduction-2026` redirects here):
what PolicyEngine is, how we prepared for Budget day, and a slide with the live
[Autumn Budget 2026 dashboard](https://ab2026-local-preview.vercel.app/uk/autumn-budget-2026)
embedded in it, where the analysis is presented. The closing slide links the
same address, with its QR code.
same address, with its QR code, and credits the Nuffield Foundation, which
funds our UK Budget analysis.

- `config.ts` controls the slide order and metadata.
- `content.ts` holds the sources, the three pillars of What PolicyEngine is,
Expand All @@ -19,5 +21,13 @@ same address, with its QR code.
here goes stale when the dashboard's data change.
- `SPEAKER-NOTES.md` gives the presenter track.

`public/images/introduction-2026/dashboard-qr.svg` encodes
`public/images/autumn-budget-2026/dashboard-qr.svg` encodes
the dashboard's address.

`public/logos/funders/nuffield-foundation-white.svg` is the Nuffield
Foundation's white logo, downloaded from nuffieldfoundation.org on 22 October
2026 (3,432 bytes, SHA-256
`b3727385be9295f8daa3938c745f87b2e00e5675130354f6394ae6b3fec5654c`). That day
its communications team asked for "funded" rather than "supported", and for
its logo, the white version on a dark background. Keep the file as
downloaded; don't recolour or redraw it.
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,6 @@ that address.

## 5. Close

The dashboard link, with a QR code for phones, and how to reach us.
The dashboard link, with a QR code for phones, and how to reach us. Thank
the Nuffield Foundation, which funds our UK Budget analysis ("funded by",
not "supported by").
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import {
WhatSlide,
} from "./slides";

export const introduction2026Config: SlideshowConfig = {
id: "introduction-2026",
title: "Analysing the UK Autumn Budget 2026 with PolicyEngine",
export const autumnBudget2026Config: SlideshowConfig = {
id: "autumn-budget-2026",
title: "Analysing the Autumn Budget 2026 with PolicyEngine",
description:
"What PolicyEngine is, how we prepared for Budget day, and the analysis, presented live on the dashboard.",
date: "2026-10-28",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ export const sources = {
export const about =
"PolicyEngine is a nonprofit building free, open-source tools that help people understand tax and benefit policies.";

// The Nuffield Foundation's credit. On 22 October its communications team
// asked for "funded" rather than "supported", and for its logo, the white
// version on a dark background. The logo is the white one from
// nuffieldfoundation.org, kept as downloaded (3,432 bytes, SHA-256
// b3727385…); its own size is 117.862 by 70.
export const funder = {
label: "Funded by",
name: "Nuffield Foundation",
logo: "/logos/funders/nuffield-foundation-white.svg",
width: 118,
height: 70,
};

// What PolicyEngine is: the rules, the households and the results. The rules
// are the main ones in the Good Growth Foundation deck's checked list.
export const pillars = [
Expand Down
31 changes: 31 additions & 0 deletions slideshows/autumn-budget-2026/funder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { funder } from "./content";

// The white logo as downloaded from nuffieldfoundation.org on 22 October. Keep
// it byte for byte: don't recolour or redraw it.
const DOWNLOADED_SHA256 =
"b3727385be9295f8daa3938c745f87b2e00e5675130354f6394ae6b3fec5654c";

describe("the Nuffield Foundation credit on the closing slide", () => {
const file = path.join(__dirname, "../../public", funder.logo);
const bytes = readFileSync(file);

it("uses the logo exactly as downloaded", () => {
expect(bytes.length).toBe(3432);
expect(createHash("sha256").update(bytes).digest("hex")).toBe(DOWNLOADED_SHA256);
});

it("matches the logo's own dimensions", () => {
const svg = bytes.toString("utf8");
const size = (name: string) => Number(svg.match(new RegExp(`${name}="([\\d.]+)"`))?.[1]);
expect(Math.round(size("width"))).toBe(funder.width);
expect(Math.round(size("height"))).toBe(funder.height);
});

it('reads "Funded by"', () => {
expect(funder.label).toBe("Funded by");
});
});
35 changes: 35 additions & 0 deletions slideshows/autumn-budget-2026/slides/ClosingSlide.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { funder, sources } from "../content";
import { ClosingSlide } from "./index";

let container: HTMLDivElement;
let root: Root;

beforeEach(async () => {
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
container = document.createElement("div");
document.body.appendChild(container);
root = createRoot(container);
await act(async () => root.render(<ClosingSlide />));
});

afterEach(() => {
act(() => root.unmount());
container.remove();
});

describe("the closing slide's funder credit", () => {
it('reads "Funded by" beside the Nuffield Foundation logo', () => {
const logo = container.querySelector<HTMLImageElement>(`img[alt="${funder.name}"]`);
expect(logo).not.toBeNull();
expect(decodeURIComponent(logo!.getAttribute("src") ?? "")).toContain(funder.logo);
expect(logo!.closest("a")?.textContent).toContain("Funded by");
});

it("links to the Nuffield Foundation's page for the project", () => {
const logo = container.querySelector(`img[alt="${funder.name}"]`);
expect(logo?.closest("a")?.getAttribute("href")).toBe(sources.nuffield.href);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,25 @@
color: var(--pe-teal);
}

/* The funder's credit: its white logo as downloaded, on the slide's dark background. */
.closingFunder {
display: flex;
align-items: center;
gap: 1.25rem;
color: inherit;
}

.closingFunderLabel {
font-size: 1rem;
font-weight: 500;
opacity: 0.85;
}

.closingFunderLogo {
width: auto;
height: 4.5rem;
}

/* Title slide: keep the logo, speakers and date clear of each other on laptops. */
@media (max-height: 760px) {
.titleCover {
Expand Down Expand Up @@ -592,6 +611,10 @@
width: 1.9rem;
height: 1.9rem;
}

.closingFunderLogo {
height: 4rem;
}
}

/* Safari on a laptop leaves less than 760px for the slide. */
Expand Down Expand Up @@ -637,4 +660,40 @@
.prepText {
font-size: 0.875rem;
}

/* The closing slide makes room for the funder's credit, so "Thank you"
stays clear of the PolicyEngine logo above it. */
.closing {
gap: 1rem;
}

.closingTitle {
font-size: 2.4rem;
}

.closingCard {
padding: 0.75rem;
}

.closingQr {
width: 6rem;
height: 6rem;
}

.closingContact {
padding: 0.35rem 0.9rem;
}

.closingContactIcon {
width: 1.7rem;
height: 1.7rem;
}

.closingFunder {
gap: 1rem;
}

.closingFunderLogo {
height: 3rem;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import SlideTitle from "@/components/layout/SlideTitle";
import { speakers } from "@/lib/speakers";
import {
about,
funder,
lastBudget,
mockBudgets,
pillars,
Expand Down Expand Up @@ -277,7 +278,7 @@ export function ClosingSlide() {
<h1 className={`${styles.closingTitle} font-display font-bold`}>Thank you</h1>
<ExternalLink href={sources.dashboard.href} className={`${styles.closingCard} hover:no-underline`}>
<Image
src="/images/introduction-2026/dashboard-qr.svg"
src="/images/autumn-budget-2026/dashboard-qr.svg"
alt="QR code for the Autumn Budget 2026 dashboard"
width={240}
height={240}
Expand All @@ -302,6 +303,16 @@ export function ClosingSlide() {
</ExternalLink>
))}
</div>
<ExternalLink href={sources.nuffield.href} className={`${styles.closingFunder} hover:no-underline`}>
<span className={styles.closingFunderLabel}>{funder.label}</span>
<Image
src={funder.logo}
alt={funder.name}
width={funder.width}
height={funder.height}
className={styles.closingFunderLogo}
/>
</ExternalLink>
</div>
</Slide>
);
Expand Down
2 changes: 1 addition & 1 deletion slideshows/good-growth-foundation-2026/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ PolicyEngine UK for the Good Growth Foundation, for a 20 to 30 minute slot.
10. Thank you, with the Autumn Budget webinar invitation and its registration QR code

Slides 2 and 9 come from the 9 October introduction deck
(`introduction-2026`, policyengine-slides #77); slide 2 merges its "What
(`introduction-2026`, since renamed `autumn-budget-2026`, policyengine-slides #77); slide 2 merges its "What
PolicyEngine is" and "How it works" slides. Slides 5 and 7 come from the
Scottish Government deck of the same day (`scottish-government-2026`), told
for the whole UK: the pipeline drops the Scotland-only stage, and the decile
Expand Down