Skip to content

Commit 0738eef

Browse files
nl0claude
andauthored
catalog: design-context scaffolding (PRODUCT.md + DESIGN.md) (#5124)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 8bb78a4 commit 0738eef

8 files changed

Lines changed: 538 additions & 0 deletions

File tree

catalog/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ npm-debug.log
1414
.idea
1515
.firebase*
1616
firebase-debug.log
17+
18+
# impeccable live-mode session state (local, not source)
19+
.impeccable/live/sessions/

catalog/.impeccable/design.json

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
{
2+
"schemaVersion": 2,
3+
"generatedAt": "2026-07-20T00:00:00Z",
4+
"title": "Design System: Quilt Catalog",
5+
"extensions": {
6+
"colorMeta": {
7+
"indigo-chassis": { "role": "primary", "displayName": "Deep Indigo Chassis", "canonical": "#282b50", "tonalRamp": ["#0b0d1e", "#1d2146", "#282b50", "#3c4070", "#555a90", "#767bae", "#9da1c9", "#c9cce4"] },
8+
"amber-indicator": { "role": "secondary", "displayName": "Amber Indicator", "canonical": "#fb8c00", "tonalRamp": ["#4a2900", "#7a4400", "#b06200", "#fb8c00", "#ffa733", "#ffc066", "#ffd699", "#ffeacc"] },
9+
"coral-signal": { "role": "tertiary", "displayName": "Coral Signal (website register)", "canonical": "#f38681", "tonalRamp": ["#5f1f1c", "#8f342f", "#c05149", "#f38681", "#f6a09b", "#fabdb3", "#fcd4cd", "#fdeae6"] },
10+
"cobalt-trace": { "role": "tertiary", "displayName": "Cobalt Trace (website register)", "canonical": "#5471f1", "tonalRamp": ["#151d4d", "#2d306d", "#3f4fae", "#5471f1", "#7690f4", "#9baff7", "#c0cdfa", "#e3e9fd"] },
11+
"web-midnight": { "role": "tertiary", "displayName": "Web Midnight (website register)", "canonical": "#19163b", "tonalRamp": ["#0a0918", "#19163b", "#2a265c", "#3f3a80", "#5a55a3", "#7d79bd", "#a5a2d4", "#d0cfea"] },
12+
"canvas": { "role": "neutral", "displayName": "Canvas", "canonical": "#fafafa" },
13+
"surface": { "role": "neutral", "displayName": "Surface", "canonical": "#ffffff" },
14+
"ink": { "role": "neutral", "displayName": "Ink", "canonical": "rgba(0,0,0,0.87)" },
15+
"ink-secondary": { "role": "neutral", "displayName": "Ink Secondary", "canonical": "rgba(0,0,0,0.54)" },
16+
"divider": { "role": "neutral", "displayName": "Divider", "canonical": "rgba(0,0,0,0.12)" }
17+
},
18+
"typographyMeta": {
19+
"display": { "displayName": "Display", "purpose": "Website-register hero headings only; never inside the app." },
20+
"headline": { "displayName": "Headline", "purpose": "Page-level headings in the app (Material h5)." },
21+
"title": { "displayName": "Title", "purpose": "Section and card headings (Material h6)." },
22+
"body": { "displayName": "Body", "purpose": "The workhorse: tables, descriptions, prose (Material body2)." },
23+
"label": { "displayName": "Label", "purpose": "Buttons and control labels — uppercase Material button treatment." },
24+
"mono": { "displayName": "Mono", "purpose": "Machine-exact identity: hashes, s3:// URIs, package handles, versions." }
25+
},
26+
"shadows": [
27+
{ "name": "overlay", "value": "0px 5px 5px -3px rgba(0,0,0,0.2), 0px 8px 10px 1px rgba(0,0,0,0.14), 0px 3px 14px 2px rgba(0,0,0,0.12)", "purpose": "Floating controls that will leave: menus, popovers (Material elevation 8)." },
28+
{ "name": "modal", "value": "0px 11px 15px -7px rgba(0,0,0,0.2), 0px 24px 38px 3px rgba(0,0,0,0.14), 0px 9px 46px 8px rgba(0,0,0,0.12)", "purpose": "Dialogs — the strongest depth in the system (Material elevation 24)." }
29+
],
30+
"motion": [
31+
{ "name": "ease-standard", "value": "cubic-bezier(0.4, 0, 0.2, 1)", "purpose": "Default easing for state transitions." },
32+
{ "name": "duration-short", "value": "150ms", "purpose": "Hover/press feedback." },
33+
{ "name": "duration-standard", "value": "250ms", "purpose": "Panel and overlay transitions; motion conveys state, never decoration." }
34+
],
35+
"breakpoints": [
36+
{ "name": "sm", "value": "600px" },
37+
{ "name": "md", "value": "960px" },
38+
{ "name": "lg", "value": "1280px" },
39+
{ "name": "xl", "value": "1920px" }
40+
]
41+
},
42+
"components": [
43+
{
44+
"name": "Primary Button",
45+
"kind": "button",
46+
"refersTo": "button-primary",
47+
"description": "The one strong action on a surface — indigo fill, uppercase label.",
48+
"html": "<button class=\"ds-btn-primary\">Create package</button>",
49+
"css": ".ds-btn-primary { background: #282b50; color: #fff; font: 500 0.875rem/1.75 Roboto, Helvetica, Arial, sans-serif; letter-spacing: 0.02857em; text-transform: uppercase; padding: 6px 16px; border: none; border-radius: 4px; cursor: pointer; transition: background 150ms cubic-bezier(0.4, 0, 0.2, 1); } .ds-btn-primary:hover { background: #1d2146; } .ds-btn-primary:focus-visible { outline: 2px solid #5471f1; outline-offset: 2px; }"
50+
},
51+
{
52+
"name": "Outlined Button",
53+
"kind": "button",
54+
"refersTo": "button-outlined",
55+
"description": "Secondary actions — indigo label, hairline border, transparent ground.",
56+
"html": "<button class=\"ds-btn-outlined\">Download</button>",
57+
"css": ".ds-btn-outlined { background: transparent; color: #282b50; font: 500 0.875rem/1.75 Roboto, Helvetica, Arial, sans-serif; letter-spacing: 0.02857em; text-transform: uppercase; padding: 5px 15px; border: 1px solid rgba(40,43,80,0.5); border-radius: 4px; cursor: pointer; transition: background 150ms cubic-bezier(0.4, 0, 0.2, 1), border-color 150ms; } .ds-btn-outlined:hover { background: rgba(40,43,80,0.06); border-color: #282b50; } .ds-btn-outlined:focus-visible { outline: 2px solid #5471f1; outline-offset: 2px; }"
58+
},
59+
{
60+
"name": "Text Field",
61+
"kind": "input",
62+
"refersTo": "input-field",
63+
"description": "Standard Material text input — quiet at rest, primary-colored on focus.",
64+
"html": "<label class=\"ds-field\"><span class=\"ds-field-label\">Package name</span><input class=\"ds-field-input\" type=\"text\" placeholder=\"prefix/suffix\"></label>",
65+
"css": ".ds-field { display: inline-flex; flex-direction: column; gap: 4px; font-family: Roboto, Helvetica, Arial, sans-serif; } .ds-field-label { font-size: 0.75rem; color: rgba(0,0,0,0.54); } .ds-field-input { font: 400 0.875rem/1.43 Roboto, Helvetica, Arial, sans-serif; color: rgba(0,0,0,0.87); background: #fff; border: none; border-bottom: 1px solid rgba(0,0,0,0.42); padding: 6px 0; transition: border-color 150ms; } .ds-field-input:hover { border-bottom-color: rgba(0,0,0,0.87); } .ds-field-input:focus { outline: none; border-bottom: 2px solid #282b50; margin-bottom: -1px; } .ds-field-input::placeholder { color: rgba(0,0,0,0.54); }"
66+
},
67+
{
68+
"name": "Chip",
69+
"kind": "chip",
70+
"refersTo": "chip",
71+
"description": "Metadata tags and filter tokens — standard Material chip.",
72+
"html": "<span class=\"ds-chip\">workflow: passing</span>",
73+
"css": ".ds-chip { display: inline-flex; align-items: center; height: 32px; padding: 0 12px; background: #e0e0e0; color: rgba(0,0,0,0.87); font: 400 0.8125rem/1 Roboto, Helvetica, Arial, sans-serif; border-radius: 16px; } .ds-chip:hover { background: #d5d5d5; }"
74+
},
75+
{
76+
"name": "Card",
77+
"kind": "card",
78+
"refersTo": "card",
79+
"description": "The working surface — white, border-delineated, 4px corners.",
80+
"html": "<div class=\"ds-card\"><div class=\"ds-card-title\">Quilt Example</div><div class=\"ds-card-body\">s3://quilt-example · 80 packages · 356.9 GB</div></div>",
81+
"css": ".ds-card { background: #fff; border: 1px solid rgba(0,0,0,0.12); border-radius: 4px; padding: 16px; font-family: Roboto, Helvetica, Arial, sans-serif; } .ds-card-title { font: 500 1.25rem/1.6 Roboto, Helvetica, Arial, sans-serif; color: rgba(0,0,0,0.87); } .ds-card-body { font: 400 0.875rem/1.43 Roboto, Helvetica, Arial, sans-serif; color: rgba(0,0,0,0.54); margin-top: 4px; }"
82+
},
83+
{
84+
"name": "App Bar",
85+
"kind": "nav",
86+
"refersTo": "app-bar",
87+
"description": "The indigo chrome band — brand, context, and global controls.",
88+
"html": "<nav class=\"ds-appbar\"><span class=\"ds-appbar-brand\">Quilt</span><span class=\"ds-appbar-ctx\">s3://quilt-example</span></nav>",
89+
"css": ".ds-appbar { display: flex; align-items: center; gap: 16px; height: 48px; padding: 0 16px; background: #282b50; color: #fff; font-family: Roboto, Helvetica, Arial, sans-serif; } .ds-appbar-brand { font-weight: 500; font-size: 1rem; } .ds-appbar-ctx { font: 400 0.875rem/1 'Roboto Mono', monospace; color: #b2bddb; }"
90+
},
91+
{
92+
"name": "Data Identity",
93+
"kind": "custom",
94+
"refersTo": "mono",
95+
"description": "Machine-exact identity: mono face, exact value, copy affordance.",
96+
"html": "<span class=\"ds-identity\"><code class=\"ds-identity-hash\">3f7a9c…e41b</code><button class=\"ds-identity-copy\" aria-label=\"Copy hash\"><svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z\"/></svg></button></span>",
97+
"css": ".ds-identity { display: inline-flex; align-items: center; gap: 6px; font-family: 'Roboto Mono', monospace; } .ds-identity-hash { font-size: 0.875rem; color: rgba(0,0,0,0.87); background: rgba(0,0,0,0.04); padding: 2px 6px; border-radius: 4px; } .ds-identity-copy { background: none; border: none; padding: 2px; color: rgba(0,0,0,0.54); cursor: pointer; border-radius: 4px; } .ds-identity-copy:hover { color: rgba(0,0,0,0.87); background: rgba(0,0,0,0.06); } .ds-identity-copy:focus-visible { outline: 2px solid #5471f1; outline-offset: 1px; }"
98+
}
99+
],
100+
"narrative": {
101+
"northStar": "The Lab Instrument",
102+
"overview": "The catalog is a well-calibrated instrument: quiet chrome, exact readouts, dense where precision demands it, and nothing on screen performs. Users are scientists and data engineers in the middle of a task — the interface earns trust the way an instrument does, through consistency, legibility, and exact values, never through decoration. The system has two registers in one codebase: the authenticated app (the instrument, light theme) and the marketing/website register (dark theme, coral and cobalt accents) — that energy is quarantined there and never enters the authenticated app.",
103+
"keyCharacteristics": [
104+
"Single-family typography (Roboto), with Roboto Mono reserved for machine-exact identity.",
105+
"Deep indigo chrome around white working surfaces; one amber accent as the indicator.",
106+
"Flat-leaning depth: borders and tonal separation first, shadows for true overlays only.",
107+
"Standard Material affordances; density serves the task, calm serves everything else."
108+
],
109+
"rules": [
110+
{ "name": "The Indicator Rule", "body": "Accents indicate — actions, selection, state. An accent on ≤10% of any app screen; an accent used as decoration is a defect.", "section": "colors" },
111+
{ "name": "The Two-Registers Rule", "body": "The dark coral/cobalt marketing palette belongs to the website register exclusively. No gradient, coral, or midnight ground ever appears inside the authenticated app; no bare canvas-gray utilitarianism leaks onto marketing pages.", "section": "colors" },
112+
{ "name": "The Mono Identity Rule", "body": "Anything content-addressed or machine-exact — hashes, s3:// URIs, package handles, version ids — renders in Roboto Mono. Prose never does.", "section": "typography" },
113+
{ "name": "The No-Display-Font Rule", "body": "Display sizes and the 300 weight exist for the website register. Inside the app, nothing outranks a Headline.", "section": "typography" },
114+
{ "name": "The Overlay-Only Rule", "body": "A shadow means 'this floats above the plane and will leave.' If it doesn't leave, it doesn't get a shadow — it gets a border.", "section": "elevation" }
115+
],
116+
"dos": [
117+
"Do keep the instrument quiet: white surfaces, indigo chrome, one accent indicating — the data is the loudest thing on screen.",
118+
"Do use Roboto Mono for every hash, URI, handle, and version (the Mono Identity Rule).",
119+
"Do delineate resting surfaces with borders and tone; save shadows for things that float (the Overlay-Only Rule).",
120+
"Do use the same control vocabulary everywhere — a control means one thing on every screen.",
121+
"Do show exact values: real counts, real timestamps, real sizes, with copy affordances."
122+
],
123+
"donts": [
124+
"Don't let consumer-SaaS gloss into the authenticated app: no gradient CTAs, no hero metrics, no marketing chrome.",
125+
"Don't drift toward cloud-console density: no wall-of-controls, no every-option-visible screens without hierarchy.",
126+
"Don't regress toward legacy lab software: no beige chrome, no modal mazes, no dead affordances — anything styled as interactive must act.",
127+
"Don't use the coral/cobalt/midnight website palette inside the app (the Two-Registers Rule).",
128+
"Don't signal state with color alone; pair color with text or iconography.",
129+
"Don't use display sizes or the 300 weight inside the app."
130+
]
131+
}
132+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"files": ["app/index.html"],
3+
"insertBefore": "</body>",
4+
"commentSyntax": "html",
5+
"cspChecked": true
6+
}

catalog/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ complete sentence without it.
2121

2222
## Changes
2323

24+
- [Added] Design-context contract for the catalog: `PRODUCT.md` (strategic context — users, positioning, brand personality, anti-references) and `DESIGN.md` (the visual-system baseline in the [design.md format](https://github.com/google-labs-code/design.md): design tokens + named rules), with an `.impeccable/` sidecar for design-aware agent tooling and pointers from README and the new `catalog/CLAUDE.md`. Documentation only — no runtime changes ([#5124](https://github.com/quiltdata/quilt/pull/5124))
2425
- [Fixed] A lost session now reliably redirects to sign-in instead of showing a generic error: both the GraphQL and REST auth-loss interceptors key on the HTTP **401** status rather than matching a single legacy error message, so any unauthenticatable request (an expired or refresh-failed session, "not logged in", etc.) bounces to `/signin`. A credential-less request that races or precedes sign-in is held rather than logged out, so the first-login handshake no longer spuriously redirects ([#5113](https://github.com/quiltdata/quilt/pull/5113))
2526
- [Removed] Embed mode — the iframe-embeddable catalog variant served at `/__embed` (a separate layout/app, with a `/__embed-debug` harness) — has been removed, along with its documentation. It was an always-on, unflagged surface with no live consumers, and dropping it collapses the standalone/packaged/embed wiring matrix that every file-view change had to account for ([#4608](https://github.com/quiltdata/quilt/pull/4608))
2627
- [Changed] Load highlight.js grammars on demand — only the ~35 languages the catalog supports (down from ~190 bundled eagerly), each fetched as its own chunk on first use; Markdown fences with unsupported labels render as plain monospace instead of being auto-detected ([#4883](https://github.com/quiltdata/quilt/pull/4883))

catalog/CLAUDE.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Quilt Catalog
2+
3+
React + Material-UI v4 (JSS) frontend for the Quilt data platform. See
4+
[README.md](./README.md) for configuration and running it locally.
5+
6+
## Design Context
7+
8+
Read before designing or changing UI:
9+
10+
- [PRODUCT.md](./PRODUCT.md) — who the catalog serves, positioning, brand
11+
personality, anti-references, design principles.
12+
- [DESIGN.md](./DESIGN.md) — the visual-system contract ([design.md
13+
format](https://github.com/google-labs-code/design.md)): design tokens plus
14+
doctrine (named rules for color, typography, elevation, components). UI
15+
changes conform to it; when a change genuinely needs the contract to move,
16+
update DESIGN.md in the same diff.
17+
- `.impeccable/` — machine sidecar and live-mode config for design-aware
18+
tooling; session state is not source.

0 commit comments

Comments
 (0)