@hegemonart/get-design-done 1.34.2 → 1.34.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,124 @@
1
+ # Lazyweb MCP — Connection Specification
2
+
3
+ This file is the connection specification for Lazyweb within the get-design-done pipeline. It lives in `connections/` alongside other connection specs. See `connections/connections.md` for the full connection index and capability matrix.
4
+
5
+ ---
6
+
7
+ Lazyweb is a **free, MCP-native visual-reference library** (250k+ real app screens). In the discover stage it is the **cost-aware default**: because it requires no paid subscription, GDD tries it **first**, before any paid reference source (Mobbin/Refero). Pitched for pricing pages, onboarding flows, "improve this existing screen" comparisons, and UI benchmarking against shipped products.
8
+
9
+ ---
10
+
11
+ ## Setup
12
+
13
+ **Prerequisites:**
14
+
15
+ - No account or subscription required — the free tier authorizes read-only UI reference search.
16
+ - A Lazyweb MCP bearer token (free) saved locally.
17
+
18
+ **Install (Claude Code):** *copy-command — never auto-run, because it writes a credential to disk (user-consent step).*
19
+
20
+ ```
21
+ # 1. save the free bearer token (chmod 600 — local config only, never commit)
22
+ mkdir -p ~/.lazyweb && printf '%s' "<your-token>" > ~/.lazyweb/lazyweb_mcp_token && chmod 600 ~/.lazyweb/lazyweb_mcp_token
23
+ # 2. install the plugin
24
+ claude plugin marketplace add https://github.com/aboul3ata/lazyweb-skill
25
+ claude plugin install lazyweb@lazyweb
26
+ ```
27
+
28
+ **Cursor / Codex / generic MCP:** register the Streamable-HTTP MCP endpoint `https://www.lazyweb.com/mcp` with the bearer token per the host's MCP-config format (follow Lazyweb's install docs for the exact block). Restart the session after install.
29
+
30
+ **Verification:**
31
+
32
+ ```
33
+ ToolSearch({ query: "lazyweb", max_results: 10 })
34
+ ```
35
+
36
+ Expect `lazyweb_search` + `lazyweb_health`. If empty, the MCP is not registered — complete the install and restart.
37
+
38
+ ---
39
+
40
+ ## When to use
41
+
42
+ In the **discover** stage, **try Lazyweb first** (it's free). Strong for:
43
+
44
+ - Pricing pages, plan/billing layouts
45
+ - Onboarding + activation flows
46
+ - "Improve this existing screen" / redesign comparisons
47
+ - UI benchmarking against real, shipped products
48
+
49
+ ## Tools available (verify via ToolSearch on first use)
50
+
51
+ - **`lazyweb_search` `{ query, limit }`** — semantic search across Lazyweb's indexed app-screen corpus.
52
+ - **`lazyweb_health`** — connection/health probe.
53
+
54
+ Names may vary between versions — treat the ToolSearch result as authoritative; do not hardcode.
55
+
56
+ ## Search strategy
57
+
58
+ Run **at least 2 queries per task** — one structural, one aesthetic (same discipline as Refero):
59
+
60
+ - **Structural** (what it IS): "pricing page three tiers", "onboarding checklist", "empty state dashboard", "settings billing".
61
+ - **Aesthetic** (how it should FEEL): "warm editorial SaaS", "neutral Swiss dashboard", "dark fintech".
62
+
63
+ ## Workflow
64
+
65
+ ```
66
+ 1. lazyweb_search "pricing page three tiers" # structural
67
+ 2. lazyweb_search "warm editorial consumer app" # aesthetic
68
+ 3. pick 3-7 that match the brief; save URLs + notes into the discover reference pack
69
+ 4. proceed to the plan stage with the pack
70
+ ```
71
+
72
+ ## Citing references in output
73
+
74
+ Always name the reference: cite as `L-01: [title] — source: lazyweb — borrow: [what you took]`. Never claim originality; show the user the logic so they can push back precisely.
75
+
76
+ ## STATE.md integration
77
+
78
+ Every stage that probes Lazyweb writes the result to `.design/STATE.md` under `<connections>`:
79
+
80
+ ```xml
81
+ <connections>
82
+ lazyweb: available
83
+ </connections>
84
+ ```
85
+
86
+ | Value | Meaning |
87
+ |-------|---------|
88
+ | `available` | ToolSearch returned non-empty results for `lazyweb` |
89
+ | `unavailable` | Lazyweb tools present but a live call errored |
90
+ | `not_configured` | ToolSearch returned empty — MCP not registered |
91
+
92
+ **Probe pattern (ToolSearch-only — no tool call, no token cost):**
93
+
94
+ ```
95
+ ToolSearch({ query: "lazyweb", max_results: 5 })
96
+ → Empty result → lazyweb: not_configured
97
+ → Non-empty result → lazyweb: available
98
+ ```
99
+
100
+ **Which stages probe Lazyweb:** the discover stage only (via `agents/design-context-builder.md`). Scan, plan, design, and verify do not use it.
101
+
102
+ ---
103
+
104
+ ## Fallback chain (cost-aware — try free before paid)
105
+
106
+ The discover stage resolves reference sources in this order:
107
+
108
+ 1. **Lazyweb (Tier 1 — FREE)** — always tried first. Use when `lazyweb: available`.
109
+ 2. **Mobbin / Refero (Tier 2 — PAID)** — fall here when Lazyweb is unavailable OR you need their depth; use whichever is bound AND has an active subscription (if both, Mobbin then Refero).
110
+ 3. **Pinterest (Tier 3)** — headless scrape, occasionally flaky.
111
+ 4. **awesome-design-md (Tier 4)** — `~/.claude/libs/awesome-design-md/design-md/` structured DESIGN.md tokens.
112
+ 5. **WebFetch (Tier 5)** — last resort.
113
+
114
+ Lazyweb never *replaces* the paid corpora — it's the free first attempt; fall through for breadth/flow-depth. Never proceed without references — that's the point of discover.
115
+
116
+ ## Anti-pattern + token handling
117
+
118
+ - Don't dump a huge set of references into the response (noise) — pick 3–7 matching the brief.
119
+ - Don't use it to justify a pre-decided direction (pull first, then decide).
120
+ - **Token handling**: the free tier authorizes no-billing UI reference reads ONLY — never purchases, paid spend, private user data, or destructive actions. The bearer token is local-config-only (`~/.lazyweb/lazyweb_mcp_token`); never commit it to git history.
121
+
122
+ ## If Lazyweb's API changes
123
+
124
+ Keep this file current. If tool names or the endpoint shift, update the examples here and adjust the routing in `skills/discover/SKILL.md` + `agents/design-context-builder.md`.
@@ -0,0 +1,119 @@
1
+ # Mobbin MCP — Connection Specification
2
+
3
+ This file is the connection specification for Mobbin within the get-design-done pipeline. It lives in `connections/` alongside other connection specs. See `connections/connections.md` for the full connection index and capability matrix.
4
+
5
+ ---
6
+
7
+ Mobbin is a **curated mobile + web product reference library** (600k+ screens, 130k+ user flows from 1,600+ shipped apps) — the de-facto standard for **flow-level** mobile references. In the discover stage it is a **Tier-2 (paid) source**: GDD tries free Lazyweb first, then falls to Mobbin or Refero depending on which the user has an active subscription for. Mobbin's edge is editorial discipline + flow-level metadata + verified-product depth, especially for mobile (iOS/Android).
8
+
9
+ ---
10
+
11
+ ## Setup
12
+
13
+ **Prerequisites:**
14
+
15
+ - An active Mobbin subscription (the MCP is included with a paid plan).
16
+
17
+ **Install (Claude Code):** *auto-run-safe — `claude mcp add` is a stateless MCP registration with zero credential filesystem-write; OAuth is handled by Mobbin in a browser on the first tool call.*
18
+
19
+ ```
20
+ claude mcp add mobbin --transport http https://api.mobbin.com/mcp
21
+ ```
22
+
23
+ On the first `mobbin` tool call, Mobbin opens a browser sign-in (OAuth) — no token is written to disk by GDD.
24
+
25
+ **Cursor / Codex / generic MCP:** register the HTTP MCP endpoint `https://api.mobbin.com/mcp` per the host's MCP-config format; sign in via the OAuth prompt on first use. Restart the session after install.
26
+
27
+ **Verification:**
28
+
29
+ ```
30
+ ToolSearch({ query: "mobbin", max_results: 10 })
31
+ ```
32
+
33
+ Expect Mobbin search/browse tools. If empty, the MCP is not registered — run the add command and restart.
34
+
35
+ ---
36
+
37
+ ## When to use
38
+
39
+ In the **discover** stage, fall to Mobbin (after free Lazyweb) when you have a subscription and need:
40
+
41
+ - **Mobile** UI references (iOS / Android platform conventions)
42
+ - **Flow-level** references (multi-screen journeys) vs single screens
43
+ - Industry-specific patterns — "how do fintech apps do KYC", "social app notification permission priming"
44
+ - Verified, curated, real-product screens
45
+
46
+ ## Tools available (verify via ToolSearch on first use)
47
+
48
+ Mobbin exposes search / browse tools (apps, screens, flows, collections) under its MCP. Names may vary between versions — treat the ToolSearch result as authoritative; do not hardcode.
49
+
50
+ ## Search strategy
51
+
52
+ Run structural + aesthetic + **flow-level** queries (Mobbin's differentiator is flows):
53
+
54
+ - **Structural / flow**: "onboarding fintech", "checkout commerce", "paywall subscription", "empty state messaging".
55
+ - **Platform**: "iOS settings", "Android bottom sheet".
56
+ - **Industry**: "KYC verification flow", "ride-hailing trip tracking".
57
+
58
+ ## Workflow
59
+
60
+ ```
61
+ 1. mobbin search "paywall subscription" # flow/structural
62
+ 2. mobbin search "calm editorial fintech" # aesthetic
63
+ 3. pick 3-5 references (NOT whole flow sets) matching the brief; save into the reference pack
64
+ 4. proceed to the plan stage with the pack
65
+ ```
66
+
67
+ ## Citing references in output
68
+
69
+ Always name the reference: cite as `M-01: [title] — source: mobbin — borrow: [what you took]`. Show the structure you borrowed (e.g., "takes Revolut's KYC step sequencing").
70
+
71
+ ## STATE.md integration
72
+
73
+ Every stage that probes Mobbin writes the result to `.design/STATE.md` under `<connections>`:
74
+
75
+ ```xml
76
+ <connections>
77
+ mobbin: available
78
+ </connections>
79
+ ```
80
+
81
+ | Value | Meaning |
82
+ |-------|---------|
83
+ | `available` | ToolSearch returned non-empty results for `mobbin` |
84
+ | `unavailable` | Mobbin tools present but a live call errored (e.g., not signed in / no subscription) |
85
+ | `not_configured` | ToolSearch returned empty — MCP not registered |
86
+
87
+ **Probe pattern (ToolSearch-only — no tool call, no API cost):**
88
+
89
+ ```
90
+ ToolSearch({ query: "mobbin", max_results: 5 })
91
+ → Empty result → mobbin: not_configured
92
+ → Non-empty result → mobbin: available
93
+ ```
94
+
95
+ **Which stages probe Mobbin:** the discover stage only (via `agents/design-context-builder.md`). Scan, plan, design, and verify do not use it.
96
+
97
+ ---
98
+
99
+ ## Fallback chain (cost-aware — try free before paid)
100
+
101
+ The discover stage resolves reference sources in this order:
102
+
103
+ 1. **Lazyweb (Tier 1 — FREE)** — always tried first.
104
+ 2. **Mobbin / Refero (Tier 2 — PAID)** — Mobbin and Refero are peers here; use whichever is bound AND has an active subscription. If both are available, **Mobbin** for mobile/flow-level depth, **Refero** for broad screen-level coverage.
105
+ 3. **Pinterest (Tier 3)** — headless scrape, occasionally flaky.
106
+ 4. **awesome-design-md (Tier 4)** — structured DESIGN.md tokens.
107
+ 5. **WebFetch (Tier 5)** — last resort.
108
+
109
+ Never proceed without references — that's the point of discover.
110
+
111
+ ## Anti-pattern
112
+
113
+ - **Don't dump entire flow sets** into the response — pick 3–5 references that match the brief.
114
+ - Don't use Mobbin for desktop-heavy work where Refero/Lazyweb are stronger (Mobbin's depth is mobile + flows).
115
+ - Don't use it to justify a pre-decided direction (pull first, then decide).
116
+
117
+ ## If Mobbin's API changes
118
+
119
+ Keep this file current. If tool names or the endpoint shift, update the examples here and adjust the routing in `skills/discover/SKILL.md` + `agents/design-context-builder.md`.
@@ -0,0 +1,113 @@
1
+ # Print-Renderer — Connection Specification
2
+
3
+ This file is the connection specification for the print-render within the get-design-done pipeline. It lives in `connections/` alongside the other connection specs (the closest analog is `connections/preview.md`, the headless-Chrome visual-truth connection). See the connection index for the full connection capability matrix (the print-renderer row is added at the 34.3 closeout).
4
+
5
+ ---
6
+
7
+ The print-render is the **verify stage's RENDERED proof for the `print` project type**. It renders the `pdf-executor`'s **Paged.js-compatible print HTML/CSS** to a **paginated PDF / page image** — the print analog of `preview.md`'s browser screenshots. Its pipeline role: after the `pdf-executor` generates the print HTML/CSS (validated by the static checker), the verify stage uses the print-render — **when available** — to surface print breakage the static validator cannot see (actual pagination, bleed placement, font embedding in the PDF, raster resolution), and narrates the result in plain English.
8
+
9
+ **Key relationship to the static validator:** the print-render is the *rendered* complement to the *static* checker `scripts/lib/print/validate-print-css.cjs`. The static validator deterministically checks constraint **classes** (`@page` present, bleed/crop-marks signal, CMYK awareness, font-embed, 300dpi — `PR-PAGE/BLEED/CMYK/FONT/DPI`); the print-render checks the **rendered output** — what actually paginates and rasterizes. The print-render is **optional** — its absence is a quality reduction, not a blocking error (D-03).
10
+
11
+ ---
12
+
13
+ ## Setup
14
+
15
+ **Prerequisites:**
16
+
17
+ - **PRIMARY — Paged.js via headless Chrome:** the same headless-Chrome family `preview.md` uses. Paged.js consumes the `@page`/bleed print CSS and paginates in headless Chrome, producing a paginated PDF. No bundled dependency is required to *probe*; the render is opt-in — like the Preview MCP, prefer a built-in / no-external-package path where possible, and where a tool IS needed it is opt-in (never installed by the pipeline).
18
+ - **ALTERNATIVE — PDFKit for Chrome-less runtimes:** where no headless Chrome is available, PDFKit constructs the page box programmatically (`new PDFDocument({ size, margins })`), embeds fonts (`doc.registerFont(...)`), and places the bleed. This is the documented Chrome-less render path.
19
+
20
+ Per **D-02 / D-10** there is **NO bundled `pdfkit`/`paged`/`puppeteer`/`playwright` dependency** and **no live render in the default `npm test`** — the print-render is an optional, opt-in enhancement the maintainer wires up in the verify stage when a renderer is present.
21
+
22
+ **Verification:**
23
+
24
+ ```bash
25
+ command -v chromium 2>/dev/null || command -v chrome 2>/dev/null || command -v node 2>/dev/null
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Why the print-render is useful
31
+
32
+ Print rendering breakage is invisible to both code review and the static validator. A print stylesheet can pass every static class-check (`validatePrintCss` returns `ok: true`) and still render broken: a table splits badly across a page boundary because a `break-inside: avoid` was missing, the bleed box does not actually extend past the trim, an `@font-face` fails to embed and the RIP substitutes a metrically-different face (reflowing the layout), a raster image that *claimed* 300dpi is upscaled and pixelates.
33
+
34
+ The static validator checks constraint **classes**; it cannot render. The print-render renders the **actual** document to a paginated PDF / page image, so pagination, bleed placement, font embedding, and raster resolution surface as visible output rather than a press reject weeks later.
35
+
36
+ ---
37
+
38
+ ## When to use the print-render
39
+
40
+ **Verify stage:** After the `pdf-executor` generates the print HTML/CSS, run the print-render — when available — to capture a paginated PDF / page proof and check for rendered breakage. The verify stage narrates the delta and notes it in `DESIGN-VERIFICATION.md`.
41
+
42
+ The print-render is **not** used at generation time. The `pdf-executor` needs no headless Chrome, no Paged.js runtime, no PDFKit, and no network to produce the print HTML/CSS — generation is gated by the static validator only (D-04/D-10).
43
+
44
+ ---
45
+
46
+ ## Availability Probe
47
+
48
+ The print-render is consumed via a CLI/binary presence check (headless Chrome / PDFKit), not ToolSearch.
49
+
50
+ **Step PR1 — renderer presence:**
51
+
52
+ ```bash
53
+ command -v chromium 2>/dev/null || command -v chrome 2>/dev/null
54
+ ```
55
+
56
+ - A headless-Chrome binary (for Paged.js) OR a PDFKit-capable runtime is found → proceed to Step PR2
57
+ - Neither → `print-renderer: not_configured` (skip all print-render steps)
58
+
59
+ **Step PR2 — render capability check:**
60
+
61
+ - A renderer is present and invokable → `print-renderer: available`
62
+ - Present but not invokable (missing flag, sandbox error) → `print-renderer: unavailable`
63
+
64
+ **Write the print-renderer status to `.design/STATE.md` `<connections>` immediately after probing** — the three-value schema `preview.md` uses (`available` / `unavailable` / `not_configured`).
65
+
66
+ ---
67
+
68
+ ## Fallback Behavior
69
+
70
+ When the print-render is `not_configured` or `unavailable`, the verify stage degrades gracefully — no error is raised.
71
+
72
+ **verify stage (`skills/verify/SKILL.md` + `agents/design-verifier.md`):**
73
+
74
+ - `print-renderer: unavailable` → skip the rendered PDF/page proof; **degrade** to the static validator `scripts/lib/print/validate-print-css.cjs` (the `PR-PAGE/BLEED/CMYK/FONT/DPI` class-checks), then a **code-only** structural audit of the print HTML/CSS; note in `DESIGN-VERIFICATION.md`: "Print render-test skipped — no headless Chrome / PDFKit; verified via the static print-CSS validator + a code-only structural audit."
75
+ - `print-renderer: not_configured` → same as unavailable; note: "Print render-test skipped — print-render not configured; verified via the static validator + a code-only audit. (Alternative: PDFKit on a Chrome-less runtime.)"
76
+
77
+ **Graceful degradation required:** the pipeline must continue when the print-render is unavailable. Missing rendered-PDF data is a **quality reduction, not a blocking error** (D-03 — the print-render is an enhancement, never hard-required, mirroring the 34.1 simulator / 34.2 Litmus connections). The static validator is always available and is the deterministic floor; the print-render is the rendered ceiling on top of it. Neither stage appends a `<blocker>` for a missing print-render connection. If a `must_have` explicitly requires rendered-PDF evidence, THEN append a blocker.
78
+
79
+ ---
80
+
81
+ ## STATE.md Integration
82
+
83
+ Every stage that probes the print-render writes the result to `.design/STATE.md` under the `<connections>` section:
84
+
85
+ ```xml
86
+ <connections>
87
+ figma: available
88
+ preview: available
89
+ print-renderer: not_configured
90
+ </connections>
91
+ ```
92
+
93
+ **Status values:**
94
+
95
+ | Value | Meaning |
96
+ |---|---|
97
+ | `available` | A headless-Chrome (Paged.js) or PDFKit renderer is present AND invokable |
98
+ | `unavailable` | A renderer binary is present but the render call errored (missing flag, sandbox) |
99
+ | `not_configured` | No headless Chrome and no PDFKit runtime — the print-render is not set up |
100
+
101
+ The verify stage re-probes at stage entry (renderer availability can change between sessions). If STATE.md already carries a `print-renderer:` status from a prior stage in the SAME session, that status can be trusted for the rest of that session.
102
+
103
+ ---
104
+
105
+ ## Caveats and Pitfalls
106
+
107
+ 1. **The print-render is an enhancement, not a requirement.** Its absence degrades to the static validator + a code-only audit and never blocks the pipeline (D-03). Do not gate a print build on a rendered PDF.
108
+
109
+ 2. **Physical-unit / DPI gotchas.** The page is a physical object — `mm`/`pt`/`in` have fixed physical sizes, `px` does not across RIPs. A render at the wrong DPI (72/96 screen vs 300 print) misrepresents raster sharpness; render at the document's declared output resolution. Bleed (~3mm) and crop marks live in the trim waste — confirm the rendered PDF actually carries them.
110
+
111
+ 3. **No bundled render dependency.** Do NOT add `pdfkit`/`paged`/`puppeteer`/`playwright` to `package.json` to make this connection work — the render is opt-in and the maintainer supplies the renderer. The default `npm test` stays hermetic (D-10).
112
+
113
+ 4. **Do NOT edit the connection index here.** The print-renderer's Active-Connections entry and Capability-Matrix row are added by the 34.3 closeout plan, not by this spec (the 34.1/34.2 disjointness pattern).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hegemonart/get-design-done",
3
- "version": "1.34.2",
3
+ "version": "1.34.4",
4
4
  "description": "A design-quality pipeline for AI coding agents: brief, plan, implement, and verify UI work against your design system.",
5
5
  "author": "Hegemon",
6
6
  "homepage": "https://github.com/hegemonart/get-design-done",
@@ -0,0 +1,223 @@
1
+ # Print Design — Constraint Catalogue
2
+
3
+ This reference is the **print/PDF constraint catalogue**: the hard print-production rules a
4
+ print-ready document MUST honor. Print is a *constrained* output surface — the screen-RGB
5
+ HTML/CSS the web executor emits has no `@page` box model, no bleed/crop marks, no CMYK
6
+ color space, no font embedding, and no 300dpi raster guidance, so it cannot be sent to a
7
+ press as-is. This file is the **authority** that the `pdf-executor` (Phase 34.3-02) generates
8
+ against and the design-verifier's print branch (34.3-03) audits against; neither re-derives
9
+ these rules. The deterministic subset of this catalogue is checked by
10
+ [`scripts/lib/print/validate-print-css.cjs`](../scripts/lib/print/validate-print-css.cjs),
11
+ whose emitted `rule` ids are the constraint-ids defined below (the spec is the authority).
12
+
13
+ It is the print sibling of the other non-web output references. The files have distinct jobs
14
+ and must not be confused:
15
+
16
+ | File | Job |
17
+ | --- | --- |
18
+ | `reference/platforms.md` (Phase 19) | Interaction **conventions** — navigation, safe areas, gestures, native typography, haptics. *Behavioral* knowledge for native/web screens. |
19
+ | `reference/native-platforms.md` (Phase 34.1) | The native **token bridge** — maps canonical CSS tokens to SwiftUI / Jetpack Compose / Flutter with a precision contract. *Token-identity* knowledge for native generators. |
20
+ | `reference/email-design.md` (Phase 34.2) | The email **constraint catalogue** — table layout, inline styles, MSO comments, dark-mode `color-scheme`. *Structural* knowledge an email template implements. |
21
+ | `reference/print-design.md` (Phase 34.3, this file) | The print **constraint catalogue** — the `@page` box model, bleed + crop marks, CMYK awareness, font embedding, and 300dpi raster fallback. *Production* knowledge a print/PDF document implements. |
22
+
23
+ Per **D-02** there is **no bundled `pdfkit` / `paged` / `puppeteer` / `playwright`
24
+ dependency**: the `pdf-executor` generates **Paged.js-compatible print HTML/CSS** as its
25
+ canonical artifact, and the PDF is rendered by the agent's contract or the *optional*
26
+ print-render connection, never by a build step. Per **D-03** print verify is this
27
+ catalogue's *static* validator plus an *optional* Paged.js-headless-Chrome / PDFKit
28
+ render-test connection that degrades to the static validator when absent. Per **D-10** the
29
+ static checks are deterministic (same CSS/HTML string → same result), with no network and
30
+ no PDF runtime, so the default `npm test` stays green on any machine.
31
+
32
+ Each constraint carries a **rule-id** (`PR-<CLASS>-NN`). Section 8 marks exactly which ids
33
+ the static validator asserts versus which are render-tested guidance only.
34
+
35
+ ---
36
+
37
+ ## 1. Purpose
38
+
39
+ Phase 19 shipped platform *references*; Phase 23 shipped the token engine; Phase 34.1 added
40
+ native generators; Phase 34.2 added the email catalogue. Print/PDF is the last untouched
41
+ product surface, and its constraints are unlike screen, native, and email alike: a physical
42
+ trim with bleed and registration marks, a *subtractive* CMYK color space instead of additive
43
+ screen RGB, a print RIP with **no web fonts** (fonts must be embedded or outlined), and a
44
+ 300dpi raster floor (vs the screen's 72/96dpi). Instead of each print document being authored
45
+ from memory, the constraints live once here (the catalogue) and once in the validator (the
46
+ statically-checkable subset), and the executor + verifier consume them. This file is the
47
+ single SC#9-print authority.
48
+
49
+ The catalogue is **prose + tables**, not an implementation. Illustrative snippets are kept to
50
+ 2–3 lines. The implementation is `validate-print-css.cjs`.
51
+
52
+ ---
53
+
54
+ ## 2. The print box model — `@page`
55
+
56
+ Print uses the CSS **`@page`** rule to define the page box: its `size` (a named page such as
57
+ `A4` / `Letter`, or an explicit `WIDTH HEIGHT` with physical units), its `margin`, and its
58
+ `marks` (`crop` / `cross`). Screen CSS has no page box at all — content flows in one
59
+ continuous viewport — so a print stylesheet that omits `@page` has no defined page geometry
60
+ and cannot paginate predictably. Paged.js consumes the `@page` CSS to paginate in headless
61
+ Chrome; PDFKit instead constructs the page box programmatically (`new PDFDocument({ size,
62
+ margins })`).
63
+
64
+ | Rule-id | Constraint |
65
+ | --- | --- |
66
+ | **PR-PAGE-01** | A print stylesheet MUST declare an `@page` rule — the print box model. Its absence means no defined page geometry. *(Statically checkable: absence of an `@page` rule is flagged.)* |
67
+ | PR-PAGE-02 | The `@page` rule SHOULD set `size` (named `A4`/`Letter` or explicit physical `WIDTH HEIGHT`) and `margin`; use `@page :first` / `:left` / `:right` for cover/spread-specific geometry. |
68
+ | PR-PAGE-03 | Control pagination with `break-before` / `break-after` / `break-inside: avoid` (and the legacy `page-break-*`) so headings, tables, and figures do not split badly across page boundaries. |
69
+
70
+ ```css
71
+ @page { size: A4; margin: 12mm; marks: crop cross; bleed: 3mm; }
72
+ ```
73
+
74
+ ---
75
+
76
+ ## 3. Bleed + crop marks
77
+
78
+ Print is **trimmed** to a bleed box: any color or image that should reach the physical edge
79
+ must extend ~**3mm past the trim line** (the *bleed*), so that slight cutting variance never
80
+ exposes a white paper edge. **Crop/registration marks** tell the printer (and the trimming
81
+ guillotine) exactly where to cut, and align the CMYK separations on press. Screen CSS has no
82
+ notion of either. The CSS print idioms are the `bleed:` descriptor and `marks: crop` (and/or
83
+ `cross`) on `@page`; Paged.js supports both. A safe area is kept *inside* the trim so no
84
+ critical content sits in the cut-tolerance band.
85
+
86
+ | Rule-id | Constraint |
87
+ | --- | --- |
88
+ | **PR-BLEED-01** | A print document targeting edge-to-edge output MUST signal a bleed box / crop marks — a CSS `bleed:` declaration, a `marks: crop\|cross` declaration, or a documented bleed/crop-marks convention. *(Statically checkable: total absence of any bleed/marks signal is flagged.)* |
89
+ | PR-BLEED-02 | Bleed is conventionally **3mm** (≈0.125in); registration marks sit in the trim waste outside the bleed box so they are removed when the sheet is cut. |
90
+ | PR-BLEED-03 | Keep a **safe area** inside the trim (≈3–5mm) — critical text and logos stay inside it so cut tolerance never clips them. |
91
+
92
+ ---
93
+
94
+ ## 4. CMYK awareness
95
+
96
+ Print is **subtractive CMYK** (cyan/magenta/yellow/key-black ink on paper), not the additive
97
+ screen **RGB** the web executor emits. Pure-RGB output risks visible color shift on press:
98
+ bright RGB blues/greens fall outside the CMYK gamut and reproduce duller, and an untagged
99
+ document leaves the RIP to guess a conversion. A print artifact must therefore signal CMYK
100
+ awareness — a `cmyk()` color, a `color-profile` / `@color-profile` reference (an ICC/CMYK
101
+ target profile), or an explicit documented CMYK-target note. Exact ICC-profile correctness
102
+ and on-press gamut matching are **render-tested**, not statically assertable (see §8).
103
+
104
+ | Rule-id | Constraint |
105
+ | --- | --- |
106
+ | **PR-CMYK-01** | A print document MUST show CMYK awareness — a `cmyk()` color value, a `color-profile` / `@color-profile` reference, or a documented CMYK-target note. *(Statically checkable: total absence of any CMYK-awareness signal — pure screen-RGB only — is flagged.)* |
107
+ | PR-CMYK-02 | Prefer named spot/`cmyk()` values for brand colors that must match on press; flag wide-gamut RGB (`display-p3`, neon RGB) that will not survive CMYK conversion. |
108
+ | PR-CMYK-03 | Rich black (e.g. `C30 M30 Y30 K100`) for large solid areas; pure `K100` for small text to avoid registration fringing. *(ICC correctness is render-tested — §8.)* |
109
+
110
+ ```css
111
+ :root { color-profile: url(./CoatedFOGRA39.icc); } /* CMYK target */
112
+ .brand { color: cmyk(0% 80% 95% 0%); }
113
+ ```
114
+
115
+ ---
116
+
117
+ ## 5. Font embedding
118
+
119
+ Print **RIPs have no web fonts** and no system-font-stack fallback chain — whatever font is
120
+ referenced must be **embedded** in the document (`@font-face` with an embedded `src:`) or the
121
+ text must be **outlined to vector**. A bare `font-family: Arial, sans-serif` system-font-stack
122
+ assumption is a print bug: the RIP may substitute a metrically-different face (reflowing the
123
+ layout) or fail to render the glyphs at all. PDFKit embeds fonts via `doc.registerFont(…)`;
124
+ Paged.js relies on `@font-face` declarations resolved before pagination.
125
+
126
+ | Rule-id | Constraint |
127
+ | --- | --- |
128
+ | **PR-FONT-01** | Fonts MUST be embedded or outlined — an `@font-face` rule with an embedded `src:`, or a documented font-embed/outline note. A bare system-font-stack assumption (no embed) is a print bug. *(Statically checkable: absence of any font-embed signal is flagged.)* |
129
+ | PR-FONT-02 | Embed only the weights/styles actually used (subset where possible) to keep the PDF small; ensure the license permits embedding. |
130
+ | PR-FONT-03 | Outline display/headline type to vector when exact rendering matters more than text selectability; keep body copy as embedded text for accessibility and reflow. |
131
+
132
+ ```css
133
+ @font-face { font-family: "Brand"; src: url(./Brand.woff2) format("woff2"); }
134
+ ```
135
+
136
+ ---
137
+
138
+ ## 6. 300dpi raster fallback
139
+
140
+ Raster/image assets need **300dpi** at final print size or they pixelate — screen assets are
141
+ authored at 72/96dpi, which is ~3–4× too coarse for press. **Vector is preferred** wherever
142
+ possible (logos, icons, rules) because it is resolution-independent; where raster is
143
+ unavoidable (photography), it must carry a 300dpi guarantee. The CSS signals are
144
+ `image-resolution: 300dpi` (or `from-image`), a `min-resolution` media query, or a documented
145
+ 300dpi note.
146
+
147
+ | Rule-id | Constraint |
148
+ | --- | --- |
149
+ | **PR-DPI-01** | Raster assets MUST carry a 300dpi raster-fallback signal — an `image-resolution:` declaration (`300dpi` / `from-image`), a `min-resolution` query, or a documented 300dpi note. *(Statically checkable: absence of any 300dpi signal is flagged.)* |
150
+ | PR-DPI-02 | Prefer vector (SVG/PDF) for logos, icons, and line art so they stay crisp at any output size; reserve raster for continuous-tone photography. |
151
+ | PR-DPI-03 | Size raster assets so their *effective* resolution at the placed dimensions is ≥300dpi; upscaling a 72dpi screen asset does not add real detail. |
152
+
153
+ ---
154
+
155
+ ## 7. Print color + units
156
+
157
+ Print prefers **physical units** (`mm` / `cm` / `pt` / `in`) over screen `px`, because the
158
+ page is a physical object — `px` has no fixed physical size across RIPs. Print-safe color,
159
+ overprint, and knockout are production concerns the executor should honor; most are
160
+ **render-tested guidance** (see §8), not statically asserted by the validator.
161
+
162
+ | Rule-id | Constraint |
163
+ | --- | --- |
164
+ | PR-UNIT-01 | Use physical units (`mm`/`cm`/`pt`/`in`) for page geometry, margins, and bleed; reserve `px` for screen. *(Guidance.)* |
165
+ | PR-COLOR-01 | **Overprint vs knockout** — small black text overprints (prints on top) to avoid registration gaps; light-on-dark knocks out. *(Render-tested — §8.)* |
166
+ | PR-COLOR-02 | **Trap/registration** — adjacent CMYK separations are trapped (slightly overlapped) so misregistration on press shows no white gap. *(Render-tested — §8.)* |
167
+ | PR-COLOR-03 | **True vector tessellation** — complex vector fills/gradients must tessellate without seams in the RIP. *(Render-tested — §8.)* |
168
+
169
+ ---
170
+
171
+ ## 8. Statically-checkable vs render-tested
172
+
173
+ This table is the **contract** the validator's `rule` ids map to. The five rule-ids below are
174
+ the deterministic subset that `scripts/lib/print/validate-print-css.cjs` asserts via
175
+ regex/string analysis of the supplied print CSS/HTML string. Every other rule-id in this
176
+ catalogue is **render-tested guidance** — verified by the optional Paged.js-headless-Chrome /
177
+ PDFKit render-test connection (34.3-02), never asserted by the static validator.
178
+
179
+ | Rule-id | Check | Statically checked by the validator? | How verified otherwise |
180
+ | --- | --- | --- | --- |
181
+ | **PR-PAGE-01** | An `@page` rule is present (the print box model) | **YES** — absence flagged | — |
182
+ | **PR-BLEED-01** | A bleed box / crop-marks signal is present (`bleed:` / `marks:` / a documented bleed-marks note) | **YES** — total absence flagged | — |
183
+ | **PR-CMYK-01** | A CMYK-awareness signal is present (`cmyk(` / `color-profile` / `@color-profile` / a CMYK note) | **YES** — total absence (pure RGB) flagged | — |
184
+ | **PR-FONT-01** | A font-embed signal is present (`@font-face` with `src:` / a font-embed/outline note) | **YES** — absence flagged | — |
185
+ | **PR-DPI-01** | A 300dpi raster-fallback signal is present (`image-resolution:` / `min-resolution` / a 300dpi note) | **YES** — absence flagged | — |
186
+ | PR-PAGE-02..03 | `size`/`margin` set, sensible page breaks | No | Render test (paginated output) |
187
+ | PR-BLEED-02..03 | 3mm bleed value, marks in trim waste, safe area | No | Render test (preflight) |
188
+ | PR-CMYK-02..03 | In-gamut brand colors, rich-black vs K100, **ICC-profile correctness** | No | Render test (press proof / ICC) |
189
+ | PR-FONT-02..03 | Subsetted/licensed embeds, vector outlining | No | Render test (PDF inspect) |
190
+ | PR-DPI-02..03 | Vector-preferred, effective ≥300dpi at placed size | No | Render test (preflight) |
191
+ | PR-UNIT-01, PR-COLOR-01..03 | Physical units, **overprint/knockout**, **trap/registration**, **true vector tessellation** | No | Render test (press / RIP) |
192
+
193
+ Notes on the five statically-checked rules:
194
+
195
+ - **Each check is a presence/absence test.** The validator flags the *total absence* of a
196
+ catalogued signal class in the supplied string; the presence of **any one** accepted signal
197
+ for a class satisfies it. The checks are independent, so a document can satisfy four classes
198
+ and trip exactly one.
199
+ - **CMYK awareness is satisfied by any of three signals.** A `cmyk()` color, a
200
+ `color-profile` / `@color-profile` reference, **or** a documented `/* CMYK … */` note each
201
+ satisfy PR-CMYK-01 on their own — a fully RGB document with an explicit CMYK-target note
202
+ still passes (the note records the production intent the RIP needs).
203
+ - **Render-tested rules are out of the static validator's scope by design.** Overprint
204
+ behavior, ICC-profile correctness, trap/registration, and true vector tessellation require
205
+ an actual PDF RIP / rendering engine — they are catalogued here as executor guidance and
206
+ verified by the optional print-render connection, never asserted statically (D-03 / D-10).
207
+
208
+ ---
209
+
210
+ ## 9. Cross-references
211
+
212
+ - [`reference/email-design.md`](./email-design.md) — the email-constraint sibling
213
+ (table layout, inline styles, MSO comments, dark mode). The non-web siblings share the
214
+ catalogue-plus-static-validator shape.
215
+ - [`reference/native-platforms.md`](./native-platforms.md) — the native token-bridge sibling
216
+ (SwiftUI / Compose / Flutter). The other non-web output surface.
217
+ - [`reference/platforms.md`](./platforms.md) — the interaction-conventions sibling.
218
+ - [`scripts/lib/print/validate-print-css.cjs`](../scripts/lib/print/validate-print-css.cjs)
219
+ — the deterministic static validator that asserts the §8 subset; its `rule` ids are the
220
+ constraint-ids defined here.
221
+ - [`reference/registry.json`](./registry.json) — this catalogue is registered as the
222
+ `print-design` entry (type `heuristic`, phase `34.3`) so the registry round-trip test
223
+ (`test/suite/reference-registry.test.cjs`) stays green (D-05, the 34.1-01 / 34.2-01 lesson).
@@ -902,6 +902,13 @@
902
902
  "type": "heuristic",
903
903
  "phase": 34.2,
904
904
  "description": "Phase 34.2 email-constraint catalogue — table-based layout (not flexbox/grid/position), inline styles (not a <style> block), MSO conditional comments for Outlook, dark-mode color-scheme/prefers-color-scheme handling, ~600px max-width, image/alt rules, and top-20-client quirks; the authority the email-executor generates against and the design-verifier email branch audits against, and the rule-id source for scripts/lib/email/validate-email-html.cjs."
905
+ },
906
+ {
907
+ "name": "print-design",
908
+ "path": "reference/print-design.md",
909
+ "type": "heuristic",
910
+ "phase": 34.3,
911
+ "description": "Phase 34.3 print-constraint catalogue — @page size/margin/marks (the print box model), bleed box + crop/registration marks, CMYK color-space awareness (subtractive, not screen RGB), font embedding/outlining (print RIPs have no web fonts), and 300dpi raster-fallback guidance; the authority the pdf-executor generates against and the design-verifier print branch audits against, and the rule-id source for scripts/lib/print/validate-print-css.cjs."
905
912
  }
906
913
  ]
907
914
  }