diff --git a/AGENTS.md b/AGENTS.md
index 26859bd..5d1c3a6 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -116,7 +116,9 @@ components/ # client components: report-view, repo-list,
# hero-search, menu-search, menu-toggle, breadcrumbs
# (route trail under the menu), workflow-sample,
# platform-config, sentry-provider,
- # toast-notification (copy feedback live region)
+ # toast-notification (copy feedback live region),
+ # report-warmup (idle-time rendering-library
+ # warming on directory pages)
lib/ # shared logic (client + RSC): routes, fetcher,
# renderer, search, utils, host, rate-limiter,
# cache-manager, error-handler, repo-submission,
@@ -281,7 +283,15 @@ coverage there when introducing new markup patterns.
the report's arrival causes no layout shift. The vizdom bridge
(`public/widgets/vizdom-bridge.js`) serves the wasm from Cache Storage
(versioned cache name) so repeat visits never re-download it regardless
- of the host's HTTP cache headers.
+ of the host's HTTP cache headers. Directory pages (landing + user
+ listing) mount `components/report-warmup.jsx`, which — after window
+ load, at main-thread idle — warms the shared report rendering libraries
+ only (the vizdom bridge module/wasm, Chart.js + svg-pan-zoom no-cors
+ into the HTTP cache, the bundled template), never report data (listings
+ can hold thousands of repositories), so the first report a visitor opens
+ renders from local caches. The landing bundle budget e2e measures
+ through the window load event for this reason: post-load prefetches and
+ warm-up fetches never delay the landing's own first paint.
- Search ``s are injected by table-enhancer — `` is FORBID in
the renderer's sanitization allow-list, so it must never appear in the
mustache template.
diff --git a/README.md b/README.md
index 386cf42..f80a011 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,8 @@ app/ # Next.js App Router (static export): layout
components/ # Client components (search combobox, hero/menu
# search, menu toggle, workflow sample, user
# listing, report view, submission form,
- # platform-config context, sentry provider)
+ # platform-config context, sentry provider,
+ # report warm-up for directory pages)
lib/ # Shared logic consumed by client components and
# RSC alike (routes, fetcher, renderer, search,
# repo-submission, error-handler, rate-limiter,
diff --git a/app/[username]/page.jsx b/app/[username]/page.jsx
index 3d6615e..c5cc004 100644
--- a/app/[username]/page.jsx
+++ b/app/[username]/page.jsx
@@ -9,6 +9,7 @@ import { userStaticParams } from '../../lib/static-params';
import { reposForUser } from '../../lib/utils';
import { isValidGitHubName } from '../../lib/routes';
import RepoList from '../../components/repo-list';
+import ReportWarmup from '../../components/report-warmup';
export const dynamicParams = false;
@@ -30,6 +31,11 @@ export default async function UserPage({ params }) {
return (