Shoot the README screenshots, and make them regenerable
CI / verify (push) Successful in 2m42s
CI / publish (push) Has been skipped

The screenshot section had been a placeholder since the shell was rebuilt as
three panes, because there was no cheap way to re-shoot and a stale image is
worse than no image. So this ships the capture, not just the captures:
scripts/screenshots.mjs takes all ten pages at 1440x900 and 393x852, in light
and dark, and screenshots-encode.py halves and re-encodes them to WebP — 16MB
of PNG becomes 1.9MB in the tree.

Two things would silently ruin a run, and the script exists to encode both.
Seeding localStorage['pig.themeMode'] is not enough: the appearance preference
is authoritative server-side and adopted after hydration, so every dark capture
snapped back to light a beat after first paint. The /api/me/profile response is
rewritten instead. And pig.sidebarOpen / pig.piggyDockOpen are per-device, so
whatever the last human left behind would otherwise leak in. The run also fails
on a wrong theme, a horizontal scrollbar or a console error — three things a
screenshot cannot show you.

Piggy is not pictured mid-conversation. It is off by default and no inference
credential exists, so such an image would be a staged transcript rather than a
capture. The README says that rather than implying the feature is missing.

Correcting what the README asserted while shooting against the running code:
read authorisation IS enforced — createReadGuardRoutes is mounted ahead of the
feature routes, and routes/learn.ts and routes/activities.ts are mounted too,
so only the HubSpot pair is still unreachable. The remaining read gap is that a
grant cannot be narrowed, there being no row-level team filter in the query
layer. Counts refreshed against the tree: 275 tests, ~47k lines, 14 migrations.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-13 21:15:45 -07:00
parent e82d5a90bf
commit d7e0cbeccc
44 changed files with 563 additions and 33 deletions
+225
View File
@@ -0,0 +1,225 @@
# Screenshots
Every page of PIG, at 1440px and at 393px, in light and in dark.
Captured from a local instance running the seed plus demo book — `pnpm run
db:seed` then `pnpm run db:demo`. Records prefixed `DEMO —` are fictional and
exist to make the arithmetic legible; everything else is the sourced, cited seed
described in [seed-data.md](seed-data.md). Every figure shown is computed by the
code in this repository, not drawn.
Piggy is absent deliberately. It is off by default (`PIGGY_ENABLED=false`, and
the Compose service sits behind a profile), and it needs an inference credential
to answer at all — so any screenshot of it mid-conversation would be a staged
transcript rather than a capture.
Desktop captures are the 1440×900 viewport, not the full scroll height: what you
see is what fits above the fold.
**Regenerating.** Start the API and the web dev server against a seeded
database, then run the capture:
```
pnpm run dev:api
pnpm run dev:web
node scripts/screenshots.mjs
```
It forces the theme, the sidebar and the dock so nothing a previous session left
in `localStorage` leaks into a capture, fails the run if any page reports a
horizontal scrollbar, a console error or the wrong theme, and re-encodes
everything to WebP. Do not hand-edit these files — re-shoot them.
Back to the [README](../README.md).
**Jump to:** [Overview](#overview) · [Margin](#margin) · [Capacity · Availability](#capacity--availability) · [Capacity · Match a requirement](#capacity--match-a-requirement) · [Growth](#growth) · [Calendar](#calendar) · [Demand pipeline](#demand-pipeline) · [Supply pipeline](#supply-pipeline) · [Accounts](#accounts) · [Contracts](#contracts)
## Overview
`/` — margin, sold ratio, idle capacity and the ranked idle-cost exposure across the whole book.
**Desktop · 1440px · light**
<img src="screenshots/overview-desktop-light.webp" alt="Overview, desktop, light">
**Desktop · 1440px · dark**
<img src="screenshots/overview-desktop-dark.webp" alt="Overview, desktop, dark">
**Mobile · 393px**
| Light | Dark |
| --- | --- |
| <img src="screenshots/overview-mobile-light.webp" alt="Overview, 393px, light"> | <img src="screenshots/overview-mobile-dark.webp" alt="Overview, 393px, dark"> |
## Margin
`/margin` — revenue against the full cost of every commitment, with break-even price per GPU-hour.
**Desktop · 1440px · light**
<img src="screenshots/margin-desktop-light.webp" alt="Margin, desktop, light">
**Desktop · 1440px · dark**
<img src="screenshots/margin-desktop-dark.webp" alt="Margin, desktop, dark">
**Mobile · 393px**
| Light | Dark |
| --- | --- |
| <img src="screenshots/margin-mobile-light.webp" alt="Margin, 393px, light"> | <img src="screenshots/margin-mobile-dark.webp" alt="Margin, 393px, dark"> |
## Capacity · Availability
`/capacity` — what is held, what is sold, what is still sellable, and what is merely reserved by a live hold.
**Desktop · 1440px · light**
<img src="screenshots/capacity-desktop-light.webp" alt="Capacity · Availability, desktop, light">
**Desktop · 1440px · dark**
<img src="screenshots/capacity-desktop-dark.webp" alt="Capacity · Availability, desktop, dark">
**Mobile · 393px**
| Light | Dark |
| --- | --- |
| <img src="screenshots/capacity-mobile-light.webp" alt="Capacity · Availability, 393px, light"> | <img src="screenshots/capacity-mobile-dark.webp" alt="Capacity · Availability, 393px, dark"> |
## Capacity · Match a requirement
`/capacity` — score a customer requirement against capacity already under commitment, then allocate against it.
**Desktop · 1440px · light**
<img src="screenshots/capacity-match-desktop-light.webp" alt="Capacity · Match a requirement, desktop, light">
**Desktop · 1440px · dark**
<img src="screenshots/capacity-match-desktop-dark.webp" alt="Capacity · Match a requirement, desktop, dark">
**Mobile · 393px**
| Light | Dark |
| --- | --- |
| <img src="screenshots/capacity-match-mobile-light.webp" alt="Capacity · Match a requirement, 393px, light"> | <img src="screenshots/capacity-match-mobile-dark.webp" alt="Capacity · Match a requirement, 393px, dark"> |
## Growth
`/growth` — deterministic attention scores over paper, activity and sold or reserved capacity, with every signal explained.
**Desktop · 1440px · light**
<img src="screenshots/growth-desktop-light.webp" alt="Growth, desktop, light">
**Desktop · 1440px · dark**
<img src="screenshots/growth-desktop-dark.webp" alt="Growth, desktop, dark">
**Mobile · 393px**
| Light | Dark |
| --- | --- |
| <img src="screenshots/growth-mobile-light.webp" alt="Growth, 393px, light"> | <img src="screenshots/growth-mobile-dark.webp" alt="Growth, 393px, dark"> |
## Calendar
`/calendar` — closes, renewals, obligations and expiring export authorisations on one quarter timeline.
**Desktop · 1440px · light**
<img src="screenshots/calendar-desktop-light.webp" alt="Calendar, desktop, light">
**Desktop · 1440px · dark**
<img src="screenshots/calendar-desktop-dark.webp" alt="Calendar, desktop, dark">
**Mobile · 393px**
| Light | Dark |
| --- | --- |
| <img src="screenshots/calendar-mobile-light.webp" alt="Calendar, 393px, light"> | <img src="screenshots/calendar-mobile-dark.webp" alt="Calendar, 393px, dark"> |
## Demand pipeline
`/demand` — the sell side. Legal sits second, because MSA and DPA execution gates delivery rather than closing the deal.
**Desktop · 1440px · light**
<img src="screenshots/demand-desktop-light.webp" alt="Demand pipeline, desktop, light">
**Desktop · 1440px · dark**
<img src="screenshots/demand-desktop-dark.webp" alt="Demand pipeline, desktop, dark">
**Mobile · 393px**
| Light | Dark |
| --- | --- |
| <img src="screenshots/demand-mobile-light.webp" alt="Demand pipeline, 393px, light"> | <img src="screenshots/demand-mobile-dark.webp" alt="Demand pipeline, 393px, dark"> |
## Supply pipeline
`/supply` — the buy side, from sourced through diligence and pricing to live and renewal.
**Desktop · 1440px · light**
<img src="screenshots/supply-desktop-light.webp" alt="Supply pipeline, desktop, light">
**Desktop · 1440px · dark**
<img src="screenshots/supply-desktop-dark.webp" alt="Supply pipeline, desktop, dark">
**Mobile · 393px**
| Light | Dark |
| --- | --- |
| <img src="screenshots/supply-mobile-light.webp" alt="Supply pipeline, 393px, light"> | <img src="screenshots/supply-mobile-dark.webp" alt="Supply pipeline, 393px, dark"> |
## Accounts
`/accounts` — both sides of the market in one book, each record carrying its confidence grade and source.
**Desktop · 1440px · light**
<img src="screenshots/accounts-desktop-light.webp" alt="Accounts, desktop, light">
**Desktop · 1440px · dark**
<img src="screenshots/accounts-desktop-dark.webp" alt="Accounts, desktop, dark">
**Mobile · 393px**
| Light | Dark |
| --- | --- |
| <img src="screenshots/accounts-mobile-light.webp" alt="Accounts, 393px, light"> | <img src="screenshots/accounts-mobile-dark.webp" alt="Accounts, 393px, dark"> |
## Contracts
`/contracts` — MSA, DPA, SLA, order form and capacity commitment, polymorphic over party and type.
**Desktop · 1440px · light**
<img src="screenshots/contracts-desktop-light.webp" alt="Contracts, desktop, light">
**Desktop · 1440px · dark**
<img src="screenshots/contracts-desktop-dark.webp" alt="Contracts, desktop, dark">
**Mobile · 393px**
| Light | Dark |
| --- | --- |
| <img src="screenshots/contracts-mobile-light.webp" alt="Contracts, 393px, light"> | <img src="screenshots/contracts-mobile-dark.webp" alt="Contracts, 393px, dark"> |
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB