@bongos/core 1.19.460 → 1.19.462
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.
- package/.bongos-core.json +145 -20
- package/.claude/skills/design/SKILL.md +11 -3
- package/docs/adr/0220-an-in-house-rebuilt-skill-is-a-first-party-skill.md +46 -0
- package/docs/adr/0221-the-impeccable-method-is-one-skill-with-sub-command-playbooks.md +36 -0
- package/docs/adr/README.md +2 -0
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +4 -0
- package/modules/ui-design/module.json +1 -1
- package/modules/ui-design/skills/PREAMBLE.md +3 -3
- package/modules/ui-design/skills/README.md +15 -1
- package/modules/ui-design/skills/design-taste-frontend/SKILL.md +136 -0
- package/modules/ui-design/skills/design-taste-frontend-v1/SKILL.md +125 -0
- package/modules/ui-design/skills/high-end-visual-design/SKILL.md +128 -0
- package/modules/ui-design/skills/impeccable/SKILL.md +143 -0
- package/modules/ui-design/skills/impeccable/reference/adapt.md +25 -0
- package/modules/ui-design/skills/impeccable/reference/animate.md +27 -0
- package/modules/ui-design/skills/impeccable/reference/audit.md +19 -0
- package/modules/ui-design/skills/impeccable/reference/bolder.md +17 -0
- package/modules/ui-design/skills/impeccable/reference/clarify.md +25 -0
- package/modules/ui-design/skills/impeccable/reference/colorize.md +22 -0
- package/modules/ui-design/skills/impeccable/reference/critique.md +15 -0
- package/modules/ui-design/skills/impeccable/reference/distill.md +26 -0
- package/modules/ui-design/skills/impeccable/reference/document.md +25 -0
- package/modules/ui-design/skills/impeccable/reference/extract.md +20 -0
- package/modules/ui-design/skills/impeccable/reference/harden.md +21 -0
- package/modules/ui-design/skills/impeccable/reference/layout.md +20 -0
- package/modules/ui-design/skills/impeccable/reference/onboard.md +22 -0
- package/modules/ui-design/skills/impeccable/reference/optimize.md +22 -0
- package/modules/ui-design/skills/impeccable/reference/polish.md +22 -0
- package/modules/ui-design/skills/impeccable/reference/quieter.md +17 -0
- package/modules/ui-design/skills/impeccable/reference/shape.md +23 -0
- package/modules/ui-design/skills/impeccable/reference/typeset.md +24 -0
- package/modules/ui-design/skills/redesign-existing-projects/SKILL.md +120 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/docs-entropy.js +5 -1
- package/src/module-api.js +1 -1
- package/tests/docs_entropy.mjs +29 -1
- package/tests/ui_design_skills.mjs +140 -9
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# `impeccable adapt` — restructure per context, never scale pixels
|
|
2
|
+
|
|
3
|
+
**When:** a surface built at one width must work at another, or in another context: a phone, a narrow pane, a print sheet, a large-text setting, a kiosk. Edits: yes, on the sheet's context rules and the states file.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case. The platform's contexts are the three the kit renders (1440 / 390 / 320), the two modes, the reduced-motion pass and the large-text setting; the world names one breakpoint and the collapse it wants.
|
|
6
|
+
|
|
7
|
+
## Native declines
|
|
8
|
+
|
|
9
|
+
An adaptation to a native mobile app, on either platform or cross-platform, is not this playbook: the surfaces here are served web pages and the native playbooks were not rebuilt. Say so in one line and route to `/design`. What survives of the principle is that porting translates idioms and never transplants them, and that a screenshot from a browser is not evidence for a native surface.
|
|
10
|
+
|
|
11
|
+
## Diagnose per context
|
|
12
|
+
|
|
13
|
+
For each context, read the shot and answer three questions: what does the visitor do here that they do not do elsewhere (a phone is one-handed and interrupted; a print sheet is read once, without a hover); what breaks (the bar wraps, the headline hits three lines, a table scrolls sideways, a hover-only affordance vanishes); what must survive (the primary action above the fold, the 24px floor, the measure).
|
|
14
|
+
|
|
15
|
+
## Restructure
|
|
16
|
+
|
|
17
|
+
- The collapse the world names comes first (the chrome world: a 60px single-row bar under 900, the hero as a static centred column, the ledger one column per row, the basics stacked). Below it, invent nothing that the wider layout does not already contain.
|
|
18
|
+
- A table becomes rows with labelled cells, not a sideways scroll; a menu becomes a disclosure; a hover affordance gains a visible twin.
|
|
19
|
+
- Large text: every container is `min-height` or content-sized, nothing `height`; the bar still holds one row at 200 percent.
|
|
20
|
+
- Print: a `@media print` block that hides the chrome and keeps the content, in ink on the pack's light ground.
|
|
21
|
+
- Nothing scales: the type roles keep their sizes, the controls keep their floor, the composition changes.
|
|
22
|
+
|
|
23
|
+
## The return
|
|
24
|
+
|
|
25
|
+
Every context the page serves named as a state or a size the kit renders, ALL CLEAN; `probe.js` PASS at 390; the ship notes list which contexts were adapted and which the page does not serve.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# `impeccable animate` — motion with a thesis
|
|
2
|
+
|
|
3
|
+
**When:** motion is asked for, a page feels dead, delight is wanted, or an ambitious effect is proposed. Edits: yes, in CSS only.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case; the world's motion grammar (the chrome world: the breath and the drift, a 20s floor on ambient loops, one authored arrival) caps everything below.
|
|
6
|
+
|
|
7
|
+
## Write the thesis before any keyframe
|
|
8
|
+
|
|
9
|
+
Three sentences in a comment at the top of the motion rules: **the one focal moment** (what arrives, once, and why the visitor should notice), **the feedback motion** (what answers a press, a hover, a change of state, on the state curve at 200 to 400ms), and **the continuity motion** (what keeps a change from being a cut: a band opening, a row entering). A page has one focal moment; a second is a `quieter` finding.
|
|
10
|
+
|
|
11
|
+
Choose every property by what it communicates: `opacity` for presence, `transform` for place and scale, `filter` on a plate for atmosphere where the world paints one. Nothing else animates, and never a layout property. Ease out from an already-visible default: the rest frame is the design, and motion is how it is reached, so a page that fails to animate is still the page.
|
|
12
|
+
|
|
13
|
+
## Delight, earned once
|
|
14
|
+
|
|
15
|
+
A personality moment is allowed when it is **tied to the product's own mechanism** (a ledger's figure ticking to its new value; a project's orb settling into its shelf), never a generic flourish. One per surface. If the sentence that justifies it is "it looks nice", it goes.
|
|
16
|
+
|
|
17
|
+
## Ambitious effects
|
|
18
|
+
|
|
19
|
+
For a technically extraordinary effect, **propose two or three directions first**, each one paragraph with what it costs at 390 and under the switch, and get the person's pick before writing any code. A direction that needs script to move (a spring, a magnetic hover, a pointer-tracked border, a shared-element transition) is named **not available** on this platform and a CSS neighbour is proposed instead; a scroll-driven one goes through `animation-timeline` behind `@supports` with a static fallback.
|
|
20
|
+
|
|
21
|
+
## The reduced-motion path, for everything
|
|
22
|
+
|
|
23
|
+
The Kill Switch at the foot of the token layer kills every animation and transition; the rest frame you designed first is what remains. A stagger comes from an `--i` custom property in the markup. A loop moves only plates and respects the world's period floor. Every rule carries a one-sentence comment naming what it communicates.
|
|
24
|
+
|
|
25
|
+
## The return
|
|
26
|
+
|
|
27
|
+
The thesis comment; the rules; the kit's reduced-motion pass green (`render.js` fails a page where anything still runs); the ship notes name the focal moment and the shots where it was seen at rest and in flight. Contrast holds at every phase where a ground moves.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# `impeccable audit` — the technical review
|
|
2
|
+
|
|
3
|
+
**When:** "is this correct?" The engineering half of a review: what the page does under the platform floors and the world's named rules, documented with locations and **fixed by nothing here**. `polish` fixes; `audit` lists.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case. In cases 3 and 4 the world's rules are the pack's fifteen and the platform floors, and an audit row that would need a `DESIGN.md` rule to judge is marked *no rule*, not failed.
|
|
6
|
+
|
|
7
|
+
## The five dimensions, each scored
|
|
8
|
+
|
|
9
|
+
Score each 0 to 3 from evidence the kit produced, never from reading the sheet alone: `render.js` for the floors at every state, size and mode, `probe.js` for the interaction contract, `contrast.js` for the pack pairs, `check-mock.js` for a mock. Then read the source for the location of every problem the shots showed.
|
|
10
|
+
|
|
11
|
+
1. **Accessibility.** Contrast in both modes; a visible focus ring on every control; one `<main>`, one `<header>`, one `<h1>`, a skip link that targets `<main>`; every control at the 24px floor; every image with `alt` or `aria-hidden`; a disclosure pattern on every menu; nothing that reads only by colour.
|
|
12
|
+
2. **Performance.** The largest contentful element is a plate or the headline, never a node a script built; fonts sized-fallback and `font-display: swap`; nothing animates a layout property; no continuous script (`requestAnimationFrame`, timers that touch layout); live DOM is `createElement` and `textContent`.
|
|
13
|
+
3. **Theming.** No literal colour outside black or white with alpha; no page `:root`; every dark rule written twice and byte-identical; no pack colour pinned as a literal; the accent spent only where the world allows.
|
|
14
|
+
4. **Responsive behaviour.** Nothing scrolls sideways at 1440, 390 or 320; the bar holds one row; the headline holds the world's line count at every width; touch targets keep the floor when the layout collapses.
|
|
15
|
+
5. **Implementation integrity.** One sheet, no inline styles, a named `z-index` scale on `body`, no dead selectors, no duplicate values that should be one token, no `innerHTML`, every state in the states file reachable, every probe green.
|
|
16
|
+
|
|
17
|
+
## The return
|
|
18
|
+
|
|
19
|
+
A table of issues: **dimension, file and line, what the shot shows, the floor or named rule it breaks, the playbook that fixes it**. Scores per dimension and the total. A row the instance's `DESIGN.md` calls for by name (the chrome world's pure-black dark, its flat bands) is not a defect and is listed under *world-sanctioned* so the next reader does not re-flag it. Save nothing except the ship notes; the kit's `report.json` is the artifact and it is regenerated each run.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# `impeccable bolder` — raise one section to its neighbours' conviction
|
|
2
|
+
|
|
3
|
+
**When:** one named section falls short of the page around it: a band that whispers between two that speak, a call to action that recedes, a headline that apologises. Edits: yes, **inside the named target only**; everything outside it stays byte-identical.
|
|
4
|
+
|
|
5
|
+
**Runs in:** cases 2 and 3; there is no bolder without a world that already sets the register.
|
|
6
|
+
|
|
7
|
+
## Only the vocabulary the system already owns
|
|
8
|
+
|
|
9
|
+
Bolder is not louder. The section is raised to the conviction its neighbours already reach, using only what the world already has: its display size ceiling, its heavier term weight, its one accent (on the pressable and the live only), its full-bleed band, its plate where the composition allows one, its scale of air. Nothing is introduced: no new colour, no new face, no gradient, no glow, no motion the thesis does not already name.
|
|
10
|
+
|
|
11
|
+
- Read the neighbours first and write down what gives them conviction (a two-line headline at the ceiling, a single door, a plate behind them, a band of air). Then give the target the same devices at the same intensity, not more.
|
|
12
|
+
- One device usually does it. Try the largest lever (size and air) before the smallest (weight), and stop at the first one that brings the section level.
|
|
13
|
+
- If the section cannot reach its neighbours without a device the world lacks, that is a `shape` finding about the section's purpose, not a reason to invent one.
|
|
14
|
+
|
|
15
|
+
## The return
|
|
16
|
+
|
|
17
|
+
The diff confined to the target's rules and markup, with one line in the ship notes naming the device used; the page rendered ALL CLEAN at all three widths in both modes; the rest of the page's shots pixel-identical to the before run.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# `impeccable clarify` — interface copy by its function
|
|
2
|
+
|
|
3
|
+
**When:** the words on the surface are unclear: a button that does not say what happens, an error that blames, a label that needs the help text to make sense. Edits: proposed, and applied only where the string is structural (a label, an action); the product's voice belongs to `copy-desk`, so voice changes are flagged to them with the proposed text.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case; copy is not world, but the instance's copy bans are (no long dash in visible copy where banned, no emoji, no exclamation in success copy).
|
|
6
|
+
|
|
7
|
+
## Rewrite by function, not by feel
|
|
8
|
+
|
|
9
|
+
Every string on the surface has one of seven jobs; classify it first, then apply that job's rule.
|
|
10
|
+
|
|
11
|
+
| Function | The rule |
|
|
12
|
+
|---|---|
|
|
13
|
+
| **Action** (buttons, links that do) | a verb and its object, in the visitor's words: "Save changes", never "Submit" or "OK"; destructive actions name the loss |
|
|
14
|
+
| **Form** (labels, placeholders, hints) | the label says what to enter, the placeholder shows the shape and is never the label, the hint says the constraint before the mistake |
|
|
15
|
+
| **Error** | what happened, what to do next, in that order, addressed to the situation and never to the visitor's fault; the field it belongs to is named |
|
|
16
|
+
| **Loading** | what is being fetched and, if it is slow, how long; never a spinner with no sentence |
|
|
17
|
+
| **Empty** | what this will hold and the one action that fills it (`onboard` designs the state; this rule writes its line) |
|
|
18
|
+
| **Success** | what is now true, plainly, without an exclamation mark |
|
|
19
|
+
| **Help** | the one fact the visitor cannot infer from the control, and nothing the label already said |
|
|
20
|
+
|
|
21
|
+
Then the hygiene: sentence case; no long dash where the instance bans it; a number is a number, not "a few"; no placeholder names or invented brands; every string that appears twice appears in one place in the source.
|
|
22
|
+
|
|
23
|
+
## The return
|
|
24
|
+
|
|
25
|
+
A table of strings: **location, function, before, after, who owns it** (structural strings changed here; voice strings flagged). The page rendered with the new strings at 390 and 320 so no label wraps into a second row in the bar; the ship notes carry the flag list for `copy-desk`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# `impeccable colorize` — colour by role, inside the fifteen
|
|
2
|
+
|
|
3
|
+
**When:** colour feels off: too many, too few, an accent spent on the wrong thing, a pairing that fails in one mode. Edits: yes, on the token layer and the rules that read it, never on the pack.
|
|
4
|
+
|
|
5
|
+
**Runs in:** cases 2 and 3 with the pack as the palette; in case 1 (a redesign) the new palette is a look from `modules/ui-design/styles/` compared with `--style <name>` on the kit and adopted by the owner, never chosen here.
|
|
6
|
+
|
|
7
|
+
## Assign roles, then map roles to tokens
|
|
8
|
+
|
|
9
|
+
Write the role list for the surface before touching a value: **ground, surface, ink, ink-muted, rule, accent (pressable and live only), a second voice where the world has one, the status vocabulary the platform owns (green, amber, red on the hall), focus, selection.** Every element on the page takes exactly one role. A role with no token is a `color-mix()` of two that exist (`color-mix(in srgb, var(--ink) 55%, var(--bg))` for a muted ink), declared once on `body`, never a literal.
|
|
10
|
+
|
|
11
|
+
- The accent lights what is pressable or live; a mark that is neither is ink, rule or nothing.
|
|
12
|
+
- No dark block pins an accent-family token to a literal; dark derives.
|
|
13
|
+
- A coloured surface tints its secondary text from its own hue, so a muted label on the accent is `color-mix()` of the accent and the ink, not a grey.
|
|
14
|
+
- The purple-blue generated gradient, gradient text and a coloured glow are refused on every pack unless the instance's `DESIGN.md` names them.
|
|
15
|
+
|
|
16
|
+
## Verify from computed values
|
|
17
|
+
|
|
18
|
+
Ratios are measured, never judged by eye: `node modules/ui-design/kit/contrast.js` for the pack's pairs (`--pack <look>` to measure a look), `render.js` for the page in both modes at every state. Body and placeholder text 4.5:1, large text and non-text 3:1, and where a ground moves under the text, at every phase of the loop. A pairing that fails in one mode is fixed in the role map, not by a mode-specific override that splits the twins.
|
|
19
|
+
|
|
20
|
+
## The return
|
|
21
|
+
|
|
22
|
+
The role list as a comment at the head of the token block; every colour on the page a `var()` or a `color-mix()`; the twins byte-identical; the contrast run clean in both modes; the ship notes name any role the world lacks as a gap for the owner, never as a private token this page added.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# `impeccable critique` — the design review
|
|
2
|
+
|
|
3
|
+
**When:** "is this good?" A judgement of the surface as a person meets it. Read-only: it returns issues and fixes and edits nothing.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case; the visitor mode from the brief sets what "good" means (a persuading page is judged on conviction and the fold, an operating page on error cost and speed, a reading page on measure and rhythm, an experiencing page on the one moment).
|
|
6
|
+
|
|
7
|
+
## The three passes, in order
|
|
8
|
+
|
|
9
|
+
1. **The heuristics, scored on a table.** Render the page first (`node modules/ui-design/kit/render.js --page <path>`) and judge the shots, not the source. One row per heuristic, a score from 0 to 2 and one line of evidence: visibility of state, match to the world's vocabulary, control and undo, consistency with the instance's other surfaces, error prevention, recognition over recall, efficiency for the returning visitor, aesthetic restraint, error recovery, help where it is needed. A row with no evidence line is not scored.
|
|
10
|
+
2. **The personas, walked.** Three archetypes and one path each, written as what they see and do at 1440 and at 390: the first-time visitor who has thirty seconds; the returning operator who does this daily and hates every extra click; the visitor with a screen reader, a keyboard, a large text setting or reduced motion. Each walk ends in the moment they would leave, or the moment they were done.
|
|
11
|
+
3. **The cognitive-load checklist.** Count, do not feel: distinct type sizes in view; distinct colours in use; competing calls to action in the first viewport; choices offered before the first meaningful one; things that move; things that need reading before the primary action is understood. Anything above the world's own ceilings (the chrome world: two lines of headline, one accent, one authored motion) is a finding.
|
|
12
|
+
|
|
13
|
+
## The return
|
|
14
|
+
|
|
15
|
+
**Three to five issues, prioritised** by cost to the visitor times how often it is met, each with the heuristic or persona that surfaced it, the shot that shows it, and the fix named as the playbook that does it (`clarify` for a copy problem, `layout` for a grouping problem, `distill` for too much, `harden` for a state that breaks). Fewer than three means the page is good and the review says so; more than five means the top five and a line that the rest exist. Where the world calls for something the checklist would count against it, say the world is the answer key and drop the row.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# `impeccable distill` — remove what does not earn its place
|
|
2
|
+
|
|
3
|
+
**When:** too much: too many elements, options, words, states, rules. Edits: yes, and they are mostly deletions.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case. Distilling toward the world means the surviving elements are the world's components and nothing else.
|
|
6
|
+
|
|
7
|
+
## The four inventories
|
|
8
|
+
|
|
9
|
+
Count before cutting. For each inventory, write the list, then mark each entry *earns its place* (the visitor's task needs it, in this mode) or *does not*.
|
|
10
|
+
|
|
11
|
+
1. **Elements.** Every band, panel, badge, dot, cue, stripe, divider. A decorative status dot, a scroll cue, a version badge, an enumerated section label and a trust strip are the usual first cuts and are banned outright in the chrome world.
|
|
12
|
+
2. **Options.** Every control the visitor can operate: filters, toggles, sorts, secondary actions. An option used by fewer than one visitor in ten goes behind a disclosure; an option nobody would miss goes.
|
|
13
|
+
3. **Copy.** Every sentence: a headline that explains the subhead, a subhead that repeats the headline, a caption under a self-evident control, help text for a labelled field. Tighten to the word; the voice stays `copy-desk`'s and the cuts are flagged to them.
|
|
14
|
+
4. **Code.** Every rule that no selector matches, every token no rule reads, every state no probe reaches, every script that only decorates. Delete, do not comment out.
|
|
15
|
+
|
|
16
|
+
## Where the function must survive
|
|
17
|
+
|
|
18
|
+
- **Progressive disclosure**: the rarely-used behind a disclosure control that follows the world's pattern (a button with `aria-expanded` and `aria-controls`), the disclosed content still in the DOM and still a state the kit renders.
|
|
19
|
+
- **Consolidation**: three similar panels become one with a switch; two bands saying one thing become one band.
|
|
20
|
+
- **Defaults**: a choice with an obvious answer becomes the answer, with the choice moved out of the way.
|
|
21
|
+
|
|
22
|
+
Never remove a state the visitor can reach (error, empty, loading); never remove the skip link, the focus ring or a control's floor; never remove a rule the world names.
|
|
23
|
+
|
|
24
|
+
## The return
|
|
25
|
+
|
|
26
|
+
The four inventories with each entry's verdict; the diff mostly red; the page rendered ALL CLEAN with fewer distinct type sizes, colours and gaps than before (state the counts); `probe.js` PASS with the same probes, because function survived.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# `impeccable document` — the design-system doc from shipped code
|
|
2
|
+
|
|
3
|
+
**When:** after a build, when an instance has no `DESIGN.md`, or when the one it has no longer describes what is served. Writes: a draft, on the claim's branch, that the owner reviews in the PR. **The root `DESIGN.md` is the instance's world; this playbook records it and never invents it.**
|
|
4
|
+
|
|
5
|
+
**Runs in:** cases 3 and 4 as a seed; case 2 as a refresh. It never runs in the same pass as `shape` (product truth and the visual system are written by different hands at different times).
|
|
6
|
+
|
|
7
|
+
## Ground truth is what shipped
|
|
8
|
+
|
|
9
|
+
Scan in this order and record only what repeats (a value used once is not a token): the custom properties on `body` and in the pack; the branding pack's `theme.ui`; `config/design-tokens.json`; the served sheets; the components the surfaces share; last, computed styles sampled from a page through the stub. Group colour into role families; map type onto the fixed hierarchy (display, headline, title, body, label, caption, data); catalogue elevation, or record flatness explicitly where the world is hairlines; keep the project's own colour format.
|
|
10
|
+
|
|
11
|
+
**Refuse to canonise a defect.** A value the craft floor forbids (a literal hex, a page `:root`, a `100vh` band, a script animation) is reported as *carried* in the draft's notes, never written into the system as a rule. **Refuse to ban a device the world natively uses**: if the chrome world's dark is pure black by decision, the draft does not call pure black a defect.
|
|
12
|
+
|
|
13
|
+
## The creative layer, asked not derived
|
|
14
|
+
|
|
15
|
+
Two short rounds of at most three questions each, and only for what the code cannot say: the named metaphor (the world's one sentence), the mood, descriptive names for the colours, the elevation philosophy, and one phrase for how components feel. Answers go into the draft's overview as the owner's words.
|
|
16
|
+
|
|
17
|
+
## The shape of the draft
|
|
18
|
+
|
|
19
|
+
The root `DESIGN.md`'s own shape, so the kit's `check-mock.js` can read its bans: frontmatter with the machine-readable tokens (colour, type, radius, spacing, components), then the fixed sections by heading: Overview, Colors (with Modes, The derived tiers, Named Rules), Typography (Hierarchy, Named Rules), Layout, Elevation and Depth, Motion, Shapes, Components, Do's and Don'ts, Accessibility Floors. Sections with nothing real are omitted, never padded. A look's `DESIGN.md` under `modules/ui-design/styles/<name>/` takes the same shape with its thirteen in lockstep with its pack.
|
|
20
|
+
|
|
21
|
+
**An existing doc is never overwritten silently.** Show it and its drift first, and offer the explicit choice: *refresh* (only the sections that drifted), *overwrite* (the whole draft, the old one in the diff), or *merge* (the draft's new rules appended under the existing headings). A project before its first build gets a *seed* with placeholders marked as such and no derived tiers.
|
|
22
|
+
|
|
23
|
+
## The return
|
|
24
|
+
|
|
25
|
+
The draft in the diff under the claim; the drift list in the ship notes; the *carried* defects listed with the playbook that would fix each; nothing written outside the branch.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# `impeccable extract` — consolidate the repeated pattern into the system
|
|
2
|
+
|
|
3
|
+
**When:** a pattern repeats across pages or components, or hard-coded values recur where a token should be. Edits: yes, across every call site, with parity proven before the old code is deleted.
|
|
4
|
+
|
|
5
|
+
**Runs in:** cases 2 and 3; in case 4 there is no system to extract into, and the extraction is a proposal for the owner.
|
|
6
|
+
|
|
7
|
+
## The threshold
|
|
8
|
+
|
|
9
|
+
**Three or more** repeats, or a hard-coded value that appears in more than one file. Below that, leave it: one-off extractions, uselessly generic components, a token per value, and merging things that only look alike are the four ways an extraction makes a codebase worse, and each is refused by name in the ship notes when the person asks for it.
|
|
10
|
+
|
|
11
|
+
## The four steps
|
|
12
|
+
|
|
13
|
+
1. **Inventory** every occurrence: file, line, the values that differ between them. Differences that are content (a label, a count) become the component's inputs; differences that are drift (a 2px taller bar) become the bug the extraction fixes; a difference that is a real design decision means these are two patterns, not one.
|
|
14
|
+
2. **Consolidate** into the existing system: a token on `body` for a value, a shared rule for a component, a fixture shape for a feed. Into the world's vocabulary (the chrome world's pill, ledger row, poster card), never a new family beside it. A markup pattern the platform's pages share becomes a documented snippet with expanded utilities, inlined marks and namespaced classes, so a page can copy it without a build step.
|
|
15
|
+
3. **Migrate every call site** and **verify parity**: `render.js` for each page before and after with the same states file, shots compared; `probe.js` PASS on each; `contrast.js` unchanged. A call site that cannot reach parity is either the drift being fixed (say which) or a second pattern (stop and split).
|
|
16
|
+
4. **Delete the superseded code** and update the catalogue: the component's line in the root `DESIGN.md` (via `document`, as a draft) and in the surface's nested `CLAUDE.md`.
|
|
17
|
+
|
|
18
|
+
## The return
|
|
19
|
+
|
|
20
|
+
The inventory; the one place the pattern now lives; the diff red where the copies were; parity shots named per page; the ship notes carry any refusal (below threshold, two patterns, a decision not a drift) in one line each.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# `impeccable harden` — make the surface survive
|
|
2
|
+
|
|
3
|
+
**When:** real data is about to arrive, or a surface was built against the neutral fixtures only. Edits: yes, on the sheet and on the states file, never on the copy's meaning.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case; hardening is floors, not world.
|
|
6
|
+
|
|
7
|
+
## The seven pressures, each a state
|
|
8
|
+
|
|
9
|
+
Add a state to the page's states file for every pressure below that the page can meet, so the kit renders it forever after instead of a session remembering to look once. The fixtures under `modules/ui-design/kit/fixtures/` are the neutral shapes; a hardening state supplies the hostile ones through the stub's `FAIL=` and `LIVE=` switches or a fixture variant.
|
|
10
|
+
|
|
11
|
+
1. **Long text**: a name at the field's limit, a title that wraps three times, a URL with no break opportunities. `overflow-wrap: anywhere` on user text, `text-overflow` only where truncation is a decision the brief made, a measure that holds.
|
|
12
|
+
2. **Empty text**: a missing name, an empty list, a zero. Every empty state is designed (`onboard` owns the first-run one; the rest are here), and a zero is a number, not a blank.
|
|
13
|
+
3. **Foreign scripts**: emoji in user text (allowed there; banned in the world's own copy), right-to-left runs inside left-to-right lines (`unicode-bidi: plaintext` on user text), CJK with no spaces, combining marks that grow the line box.
|
|
14
|
+
4. **Translation expansion**: every label survives a 40 percent longer string without clipping or a second row in the bar; no control's width is a magic number.
|
|
15
|
+
5. **Failure**: the feed 5xx, the feed slow, the feed a different shape; a state each, and the page still a complete composition with the failure said in the instance's voice (a string flagged to `copy-desk`, not invented).
|
|
16
|
+
6. **Permission**: signed out, signed in below the rank the surface expects, signed in and disabled; the stub's `AUTH=1` and the fixtures' builder are the two ends.
|
|
17
|
+
7. **Scale**: a list of a thousand rows, a plate that never loads, a table wider than 320. Pagination or a window, never a scroll of the whole document sideways.
|
|
18
|
+
|
|
19
|
+
## The return
|
|
20
|
+
|
|
21
|
+
The new states named in the states file and rendered ALL CLEAN in both modes at all three widths; `probe.js` still PASS; the ship notes list which pressures the page could not meet and why (a surface with no user text has no long-text state, and says so). Nothing was made prettier; that is `polish`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# `impeccable layout` — reading order, grouping, rhythm, density
|
|
2
|
+
|
|
3
|
+
**When:** a page reads in the wrong order, groups the wrong things, has no rhythm, or is too dense or too thin for its mode. Edits: yes, on structure and spacing; never a rescale.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case. The world supplies the container, the breakpoint, the rhythm scale and the archetypes (the chrome world: full-width bands under a hairline, a 1180px wrap, one breakpoint at 900); this playbook arranges inside them.
|
|
6
|
+
|
|
7
|
+
## Diagnose four things, from the shots
|
|
8
|
+
|
|
9
|
+
1. **Reading order.** Read the 1440 shot top-left to bottom-right and write down the order the eye takes; then read the DOM order. Where they differ, the DOM is wrong (a screen reader gets the DOM) or the composition is (the eye gets the composition); fix the one that is wrong, never with `order` alone.
|
|
10
|
+
2. **Grouping.** Things that belong together sit closer to each other than to anything else; a group has one heading, one purpose, one boundary (a hairline, air, never a card where the world bans one). A group with two purposes is two groups.
|
|
11
|
+
3. **Rhythm.** Every vertical gap is a step on the world's scale, tight inside a group and generous between groups, with more above a heading than below it. Measure the computed gaps; a page with eleven distinct gap values has no rhythm.
|
|
12
|
+
4. **Density.** The visitor mode sets it: an operating surface holds more per band than a persuading one. Density is facts per band, not padding; the 24px floor and the measure never give.
|
|
13
|
+
|
|
14
|
+
## Restructure, do not rescale
|
|
15
|
+
|
|
16
|
+
The fix is a different arrangement at the same size, never a smaller font or a tighter container to make things fit. Adjacent bands never share a layout family (split, full-bleed, ledger, tile grid, single measure each appear once before any repeats); a grid has exactly as many cells as items; a bento with a filler tile is a list.
|
|
17
|
+
|
|
18
|
+
## The return
|
|
19
|
+
|
|
20
|
+
The new structure rendered at all three widths in both modes, ALL CLEAN; `probe.js` still PASS; the ship notes carry the before-and-after reading order as two numbered lists and the gap values as one line.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# `impeccable onboard` — first run, empty states, hints and a short tour
|
|
2
|
+
|
|
3
|
+
**When:** a surface has a first time: an empty ledger, an unconfigured project, a page the visitor has never seen. Edits: yes, but only on the empty and first-run states and whatever carries a hint.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case; onboarding is content and sequence, and the world supplies the form.
|
|
6
|
+
|
|
7
|
+
## The one rule
|
|
8
|
+
|
|
9
|
+
**The fastest path to first value.** Not the fullest introduction: the shortest sequence from arriving to having done the one thing the surface exists for. Count the steps before the first meaningful result and remove every one that a default could take.
|
|
10
|
+
|
|
11
|
+
## The four devices, in order of preference
|
|
12
|
+
|
|
13
|
+
1. **The designed empty state.** The page with nothing in it is a composition, not a blank: what this will hold, the one action that fills it, and nothing else. It uses the world's components (the chrome world's door pill, its hairline bands); it never carries an illustration invented for the occasion, because imagery is hero plates only.
|
|
14
|
+
2. **A contextual hint**, placed where the thing it explains is, shown once, dismissable in one press, and **never shown again after dismissal** (a flag in `localStorage` keyed by the hint, read at render, never a server call). A hint that explains a control the world already makes obvious is removed.
|
|
15
|
+
3. **A short tour**: at most three stops, each one sentence, each pointing at a real element on the page, skippable from the first stop with a control that clears the whole tour. A tour that needs a fourth stop is a `distill` finding on the page.
|
|
16
|
+
4. **Progressive defaults**: a form prefilled with the sensible value so the first submit works, the advanced choices behind a disclosure.
|
|
17
|
+
|
|
18
|
+
Everything is **always skippable and never repeated after dismissal**. Nothing blocks the page; nothing moves under the visitor's hands; the tour respects the switch like everything else.
|
|
19
|
+
|
|
20
|
+
## The return
|
|
21
|
+
|
|
22
|
+
The first-run and empty states named in the states file and rendered; the hints' dismissal proven by a probe (open, dismiss, reload, absent); every string flagged to `copy-desk` in the ship notes because voice is theirs. A one-line note of how many steps the first value now takes, against how many before.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# `impeccable optimize` — fix the measured bottleneck
|
|
2
|
+
|
|
3
|
+
**When:** the surface feels slow, or a review suspects it is. Edits: yes, on whatever the measurement names, and nothing else.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case; performance is floors, and the platform's surfaces are static markup, one sheet and script only for live data, so the usual suspects are few.
|
|
6
|
+
|
|
7
|
+
## Measure first, on the real thing
|
|
8
|
+
|
|
9
|
+
Suspicion is not a finding. Serve the page through the stub (`kit/serve.js`, the instance's real transforms) and measure with the playwright plugin or the browser's own tooling: the largest contentful paint and which element it was; layout shift and which element moved; the long tasks and which script ran; the bytes and which asset carried them; the render count under a live refresh. Write the numbers down before changing anything. **Fix the one thing the numbers name**, re-measure, and stop when the number is under the floor, not when the code looks fast.
|
|
10
|
+
|
|
11
|
+
## The floors and their usual causes
|
|
12
|
+
|
|
13
|
+
- **The largest paint is a plate or the headline**, never a node a script built. Cause: markup built from a fetch; fix: real values baked into the markup and refreshed live.
|
|
14
|
+
- **Nothing shifts.** Cause: an unsized image, a web face without a sized fallback, a band that appears late; fix: `width`/`height` or `aspect-ratio` on every plate, `size-adjust` on the fallback face, the band in the markup from the start.
|
|
15
|
+
- **No layout property animates.** Cause: a transition on `height`, `top`, `margin`; fix: `transform` and `opacity` only, and a `grid-template-rows: 0fr → 1fr` for an opening band.
|
|
16
|
+
- **No continuous script.** Cause: a `requestAnimationFrame` loop, a timer that touches layout; fix: delete it, the switch forbids it anyway.
|
|
17
|
+
- **Bytes**: one sheet, plates as a black JPEG plate plus a WebP alpha cutout at production size, fonts subset to the scripts the copy uses, no library for something CSS does.
|
|
18
|
+
- **Live data** is `createElement` and `textContent` into existing nodes, batched per refresh, never `innerHTML` and never a rebuild of the list.
|
|
19
|
+
|
|
20
|
+
## The return
|
|
21
|
+
|
|
22
|
+
The numbers before and after on one line each; the one change and why the measurement named it; `render.js` still ALL CLEAN and `probe.js` still PASS; a note of what was **not** changed because the measurement did not name it.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# `impeccable polish` — the final pass over a whole path
|
|
2
|
+
|
|
3
|
+
**When:** a whole user path (sign in, pick a project, open the wizard, finish) before it ships, or after `audit` has listed what is wrong. Edits: yes, and every edit is classified first.
|
|
4
|
+
|
|
5
|
+
**Runs in:** cases 2 and 3 mostly; a polish in case 4 is limited to the platform floors because there is no world to polish toward.
|
|
6
|
+
|
|
7
|
+
## Classify every drift before touching it
|
|
8
|
+
|
|
9
|
+
Walk the path in the kit's shots, every state, both modes, three widths. Each thing that is off goes in one of four buckets, and the bucket decides where the fix lives:
|
|
10
|
+
|
|
11
|
+
| Bucket | What it looks like | Fix at |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| **Missing token** | a value the world names but the sheet spells out (a literal radius, a hand-typed grey, a duration) | the token layer on `body`: use the existing token, or name the gap in the ship notes if the world has none |
|
|
14
|
+
| **One-off implementation** | the world's component rebuilt slightly differently on this page (a second pill, a bar that is 2px taller) | the shared rule: reuse the world's component, delete the copy |
|
|
15
|
+
| **Conceptual mismatch** | the page speaks a different mode than its brief (a ledger that persuades, a landing that operates) | the brief, then `layout` or `distill`; not a polish edit |
|
|
16
|
+
| **Local defect** | a typo in a selector, a missing state, a wrong breakpoint, an orphaned rule | the line |
|
|
17
|
+
|
|
18
|
+
**Fix the cause at the narrowest correct level.** A missing token fixed on one page will drift again on the next; a local defect fixed in the token layer changes every page. Never fix a conceptual mismatch in a polish pass: name it and stop that thread.
|
|
19
|
+
|
|
20
|
+
## Order and proof
|
|
21
|
+
|
|
22
|
+
Fix all the local defects in one batch, then the one-offs, then the tokens, rendering once after each batch and never after each edit. A path is polished when `render.js` is ALL CLEAN for every page on it, `probe.js` is PASS, and the ship notes list every drift by bucket with the line that fixed it. The mismatches go to the notes as open decisions with the playbook that owns them.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# `impeccable quieter` — reduce without losing the point of view
|
|
2
|
+
|
|
3
|
+
**When:** the surface is too loud: saturated where it should rest, heavy where it should breathe, decorated where it should be plain, moving where it should be still. Edits: yes, across the surface, each a reduction.
|
|
4
|
+
|
|
5
|
+
**Runs in:** cases 2 and 3; in case 4 quieter means the neutral pack and the floors, and nothing more.
|
|
6
|
+
|
|
7
|
+
## Quiet is precision, not grayscale
|
|
8
|
+
|
|
9
|
+
Reduce four things, in this order, and stop at the first level where the page rests: **saturation** (the accent only on the pressable and the live; a second voice back to the world's second token; every other coloured thing to ink or rule), **weight** (the term weight only where a term is; headlines at the world's display weight; no bold as emphasis in prose), **decoration** (no dots, stripes, glows, badges, numbering, cues; a hairline where a box was; air where a divider was), **motion** (the one focal moment kept, everything else at rest; ambient loops slower or gone).
|
|
10
|
+
|
|
11
|
+
What must survive, and is checked after each level: **hierarchy** (the eye still lands on the headline, then the action, then the proof), **personality** (the world's display voice, its one warm thing, its plate if it had one), and **the point of view** (a quieter page still argues the same thing; if it now says nothing, the reduction went one level too far and the last step is reverted).
|
|
12
|
+
|
|
13
|
+
Never quieten by desaturating everything to grey, by lowering contrast below the floor, by hiding a state, or by removing the one plate the composition was built around.
|
|
14
|
+
|
|
15
|
+
## The return
|
|
16
|
+
|
|
17
|
+
The four levels applied, named in the ship notes with the level at which the page rested; the page rendered ALL CLEAN in both modes; the contrast run unchanged or better; the counts of distinct colours, weights and moving things before and after on one line.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# `impeccable shape` — the bounded discovery interview
|
|
2
|
+
|
|
3
|
+
**When:** before any new visual work, or when the brief block in the ship notes has holes (no audience, no primary action, no mode). Planning only: **no code, no contract, no persistence** beyond the brief block itself.
|
|
4
|
+
|
|
5
|
+
**Runs in:** any of the four cases. In case 4 (no visual authority) it is also where the session says out loud that the neutral pack is the world.
|
|
6
|
+
|
|
7
|
+
## The interview
|
|
8
|
+
|
|
9
|
+
One round by default, **two or three questions per round**, each about outcomes and product behaviour rather than implementation (the owner may not be an engineer). Prefer the harness's structured question widget where one exists; otherwise three numbered questions in one message. A second round only when the first left a fork open, and never a third.
|
|
10
|
+
|
|
11
|
+
Pick the questions from what the homes do not already answer. Read `docs/project-context.template.md` and the task body first; ask nothing they settle.
|
|
12
|
+
|
|
13
|
+
- **Who is this for and what do they come to do?** The visitor mode falls out of the answer: persuade, operate, read, or experience. Pick it from the surface, not the product.
|
|
14
|
+
- **What is the one action, and what proof makes them take it?** A ledger's proof is the data itself; a landing's is a plate and a sentence; a settings page's is that nothing is hidden.
|
|
15
|
+
- **What must not change?** The named rules of the world bind by default; the question is which existing content, behaviour or identity is out of scope for this pass.
|
|
16
|
+
- **Refine or redesign?** Say what each means in one line (refinement keeps the look; redesign keeps the truth and replaces the look) and make them pick. No blend.
|
|
17
|
+
- **Mockup first or straight to code?** Asked once, as its own question, and recorded in the brief; a surface with a settled world usually goes straight to code and proves itself in the kit.
|
|
18
|
+
|
|
19
|
+
Where the product-truth file is still the scaffold, the round covers its sections too (platform, users, purpose, positioning, constraints, brand commitments, accessibility), **at least one real answer** before anything is treated as known; an inferred fact is labelled *inferred* in the brief and disclosed up front. Invented social proof, pricing and figures are banned; an undecided fact is recorded as *undecided*, never padded.
|
|
20
|
+
|
|
21
|
+
## The return
|
|
22
|
+
|
|
23
|
+
A confirmed written brief in the brief block's shape, read back to the person in full and confirmed with one word before it is written into the ship notes. Proposed edits to `docs/project-context.template.md` are listed as a diff for the owner, not applied by this playbook. Then hand off: a new marketing surface goes to `design-taste-frontend`, a working surface to the `/design` loop, and a change to an existing one to the playbook the brief names.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# `impeccable typeset` — type on a role scale, on the pack's faces
|
|
2
|
+
|
|
3
|
+
**When:** type feels off: sizes that do not relate, a headline that wraps to three lines, prose that runs wide, numbers that jitter. Edits: yes, on the type tokens and the rules that read them.
|
|
4
|
+
|
|
5
|
+
**Runs in:** every case. The faces are the pack's two stacks in every case; a brief that names another typeface gets the nearest face the pack carries and a line in the notes.
|
|
6
|
+
|
|
7
|
+
## The role scale
|
|
8
|
+
|
|
9
|
+
Name the roles the surface uses before setting a size: **display, headline, title, body, label, caption, data**. Each maps to one token on `body` (size, line-height, weight, tracking, and the face it takes from the two stacks). A size that belongs to no role is deleted. The world's hierarchy caps the count; the chrome world's display voice is light, tight-tracked and lowercase, its headline holds two lines, its labels are a mono face and are the only place it shouts.
|
|
10
|
+
|
|
11
|
+
- **Measure**: prose 65 to 75 characters (`max-width` in `ch`), and the measure is spent on the reading text, not on a container.
|
|
12
|
+
- **The display ceiling**: a `clamp()` whose upper bound is the world's, and a tracking floor at display sizes so a big face does not fall apart.
|
|
13
|
+
- **Balance**: `text-wrap: balance` on headings, `pretty` on prose, and no orphaned last word on a headline at 1440 or 390.
|
|
14
|
+
- **Data**: `font-variant-numeric: tabular-nums` on anything a ledger produced, so a live refresh does not reflow the row.
|
|
15
|
+
- **Loading**: `font-display: swap` with a fallback sized to the web face (`size-adjust`, `ascent-override`) so nothing shifts when it arrives.
|
|
16
|
+
- **Case**: sentence case for headlines and prose, the world's lowercase for its display voice and controls, uppercase only in a label face the world names.
|
|
17
|
+
|
|
18
|
+
## Verify from computed values
|
|
19
|
+
|
|
20
|
+
The kit's shots at 1440 / 390 / 320 with real copy from the fixtures: no overflow, the headline within the world's line count, the measure within range, the bar on one row. Measure the rendered line length, do not estimate it.
|
|
21
|
+
|
|
22
|
+
## The return
|
|
23
|
+
|
|
24
|
+
The role tokens declared once; every text rule reading a role; the shots clean at all three widths in both modes; the ship notes list any role the world's `DESIGN.md` does not name, as a gap for the owner rather than a size this page invented.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: redesign-existing-projects
|
|
3
|
+
description: Upgrades an existing site or app in place, in whatever framework and styling method it already uses, without breaking it. A fixed three-step sequence (scan the stack, diagnose against a written audit, apply targeted fixes), the seven-group audit (typography, colour and surface, layout, interaction, content, code and omissions) with the instance's world as the answer key, a catalogue of upgrade techniques marked CSS-only or not available, and a fixed impact-per-risk fix order. Triggers on "redesign this", "upgrade the existing page", "make the current X premium", "audit this UI", "this page looks generic, fix it". Rebuilt in-house from the taste-skill rebuild spec (task 1003325, ADR 0198); keeps the stack, never migrates frameworks, images are hero plates only.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
7
|
+
> **Platform preamble — read before any rule below.** This skill ships with the `ui-design` module (vendored from a scanned origin, or rebuilt in-house from a spec) and runs INSIDE an instance's world, which it reads first and never overrides.
|
|
8
|
+
>
|
|
9
|
+
> 1. **Load the world before any taste rule.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui` is the fifteen tokens: <redacted> colours and two font stacks), `config/design-tokens.json` over `config/design-tokens.neutral.json`, and `DESIGN.md` at the repo root: the instance's palette and derived tiers, faces, materials, motion grammar, components, and its Do's and Don'ts. Where an instance has no `DESIGN.md`, the neutral pack is the world and the platform floors in item 6 are the whole rulebook; say so and build to them. Never invent a palette.
|
|
10
|
+
> 2. **The fifteen-token contract is the only colour source.** Every colour is a `var()` or a `color-mix()` of the fifteen; the only legal literal is pure black or white with alpha as a scrim, mask or halo. No page `:root` (page tokens live on `body`), and every dark rule is written twice: `:root[data-mode="dark"]` and its `prefers-color-scheme` twin.
|
|
11
|
+
> 3. **A style skill produces variants INSIDE that world, never a second world.** The look this skill carries (its palette, faces, materials, mood boards) is a reference for composition and craft; the instance's tokens and faces replace it. Changing the world is the owner's decision and an ADR, not a session's taste.
|
|
12
|
+
> 4. **Images are for hero plates and hero objects only.** UI is built from templates and the instance's world, not painted; any image-generation step below applies to text-free plates and hero objects, never to controls, cards, text, or a screenshot of a screen.
|
|
13
|
+
> 5. **The instance's taste bans apply and win.** Read them from its `DESIGN.md`. Cloud Bongos's own (no em dash or en dash in visible copy, no emoji, no gradient text, no three-equal-card row, no fake screenshot built from divs) are that instance's, not the module's; where this skill's rules conflict with an instance's bans, the instance wins.
|
|
14
|
+
> 6. **The platform floors hold on every instance** and a `DESIGN.md` may tighten them, never loosen them: every control clears 24px on both sides (primary pills 46–48px); AA in both modes (4.5:1 body text, 3:1 large text and non-text) measured from the real stylesheet; and the Kill Switch, `@media (prefers-reduced-motion: reduce)` at the foot of the token layer killing every animation and transition, no motion authored in JavaScript, and a rest frame that is a complete composition on its own.
|
|
15
|
+
> 7. **Look before you ship.** Render the real surface through the module's kit before and after (`/design` Step 2 and `docs/recipes/ui-look-before-you-ship.md`: every state at 1440 / 390 / 320 in dark and light, audited against the floors); a page with no states file gets one first, and new interactive code ships with a pin in the page's own test file.
|
|
16
|
+
>
|
|
17
|
+
> The rules below are the skill's own. A vendored copy carries a `PROVENANCE.md` beside this file naming the origin, the pinned commit, the licence and the scan verdict it was vendored under; an in-house rebuild names its rebuild spec and its ADR in the section right after this block.
|
|
18
|
+
<!-- END PLATFORM PREAMBLE -->
|
|
19
|
+
|
|
20
|
+
## Rebuilt from
|
|
21
|
+
|
|
22
|
+
This skill is an **in-house rebuild**, not a vendored copy. Its documented functionality comes from `Leonxlnx/taste-skill` @ `<redacted>` (MIT; the `redesign-skill` entry), which `/scan-before-install` reduced to `dangerous` at the default tier on 2026-08-28, so under [ADR 0198](../../../../docs/adr/<redacted>.md) it could land only as a REBUILD-SPEC. The spec is the body of [task 1003325](https://cloudbongos.com/builders#/task/1003325); this file implements its requirements from scratch, **no upstream bytes consulted or copied**; the landing shape is [ADR 0220](../../../../docs/adr/<redacted>.md).
|
|
23
|
+
|
|
24
|
+
What changed in translation, on purpose: the upstream audit carried its own opinions (pure black backgrounds are a defect, flat sections are unfinished); here **the instance's world is the answer key**, so an audit row is a defect only where the world does not call for it (the chrome world's dark ground is pure black by the owner's decision, and its bands are flat by design). The upgrade catalogue marks each technique **CSS-only or not available** on a platform where nothing moves in script. Imagery follows the owner's rule.
|
|
25
|
+
|
|
26
|
+
## The three steps, in order
|
|
27
|
+
|
|
28
|
+
1. **Scan.** Identify the framework and the styling method from the tree, not from memory: the instance's `package.json`, the directory's nested `CLAUDE.md`, the sheet the page loads, `config/design-sources.json` (which tool authored the surface). On a platform surface that is static HTML, one sheet and the instance's transforms. Then load the world (the preamble's order) and the page's states file. Render **before** with the kit and keep the shots: `node modules/ui-design/kit/render.js --page <path> --out <dir>/before`.
|
|
29
|
+
2. **Diagnose** against the written audit below. Every row is a yes or a no with a line reference; the rows that are "yes" and not called for by the world are the work. Write the list in the ship notes before touching anything.
|
|
30
|
+
3. **Fix**, in the impact-per-risk order below, one group per commit, and render **after** with the same states file. The diff names which audit rows it closed.
|
|
31
|
+
|
|
32
|
+
## The audit (the world is the answer key)
|
|
33
|
+
|
|
34
|
+
### Typography
|
|
35
|
+
|
|
36
|
+
- Default faces where the pack names others: the two stacks are the faces.
|
|
37
|
+
- Weak headline presence: display size, weight and tracking are the world's (the chrome world: 300, `-0.042em`, two lines).
|
|
38
|
+
- Over-wide measure: prose above 65ch.
|
|
39
|
+
- Only two weights in use: the world's hierarchy has display, body and a term weight; a page that uses two is flat.
|
|
40
|
+
- Proportional numerals in data: every real number is `tabular-nums`.
|
|
41
|
+
- Missing tracking adjustments on display sizes; orphaned last words on headlines (`text-wrap: balance` on headings, `pretty` on prose).
|
|
42
|
+
|
|
43
|
+
### Colour and surface
|
|
44
|
+
|
|
45
|
+
- **Pure black backgrounds** where the world does not call for one (the chrome world does; a page inside it is not in violation).
|
|
46
|
+
- Oversaturated or multiple accents: the accent is the pack's `accent`, once; a second voice is `sea`.
|
|
47
|
+
- Mixed warm and cool greys: only the pack's neutral ramp.
|
|
48
|
+
- The purple-blue generated gradient signature; gradient text; a neon glow: banned on every pack.
|
|
49
|
+
- Untinted shadows: a shadow, where the world has one, is tinted with `ink`.
|
|
50
|
+
- Zero texture: a defect only where the world has a material (a plate, a screen); the chrome world's texture is its plate, and nothing else is painted.
|
|
51
|
+
- Inconsistent light direction across plates, shadows and highlights.
|
|
52
|
+
- **A lone inverted section** inside an otherwise light or dark page: the copy-paste accident; the chrome world bans a black panel on a light page.
|
|
53
|
+
- **Flat text-on-plain-ground sections** read as unfinished **where the world builds depth**; where the world is hairlines by design, a flat band is the design.
|
|
54
|
+
|
|
55
|
+
### Layout
|
|
56
|
+
|
|
57
|
+
- Total symmetry; three equal feature columns; every card the same size.
|
|
58
|
+
- Fixed `100vh` sections: the world's floored stage or `100dvh`.
|
|
59
|
+
- Flexbox percentage maths for a grid: `grid` with named tracks.
|
|
60
|
+
- Missing `max-width`: the container is `spacing.container`.
|
|
61
|
+
- Uniform radii everywhere: the world's three-step radius tier (pill, panel, tile), and nothing between.
|
|
62
|
+
- No overlap or depth where the world has a cascade; misaligned baselines across side-by-side cards.
|
|
63
|
+
|
|
64
|
+
### Interaction
|
|
65
|
+
|
|
66
|
+
- Missing hover, press, focus, loading, empty or error states: every one is a state the page's states file names and the kit renders.
|
|
67
|
+
- Dead placeholder links (`href="#"`): a link goes somewhere or is not a link.
|
|
68
|
+
- No active-page indicator in navigation (the world's lit hairline, `aria-current`).
|
|
69
|
+
- Animation of layout-triggering properties; motion in script; anything that escapes the Kill Switch.
|
|
70
|
+
|
|
71
|
+
### Content
|
|
72
|
+
|
|
73
|
+
Text is `copy-desk`'s; this audit **flags** and the ship notes carry the flags. Placeholder person names, fake round numbers, invented startup brand names, cliche marketing verbs, exclamation marks in success copy, passive voice, identical dates, repeated avatars. The fixtures under `modules/ui-design/kit/fixtures/` are the neutral builder and the real feed shapes; a page rendered with them shows whether the layout survives real data.
|
|
74
|
+
|
|
75
|
+
### Code and omissions
|
|
76
|
+
|
|
77
|
+
- Div soup where the world requires structure: one `<main>`, one `<header>`, one `<footer>`, one `<h1>`, a skip link that targets `<main>`.
|
|
78
|
+
- Inline styles; arbitrary `z-index` values (a named scale on `body`); missing `alt` text; missing social meta tags; imports that do not exist.
|
|
79
|
+
- Missing legal links (the footer row: privacy, terms, contact), a 404 that renders the world (the platform's game-less 404 tail), field validation, the skip link (a floor, not a nicety), a consent banner where the instance needs one.
|
|
80
|
+
|
|
81
|
+
## The upgrade catalogue
|
|
82
|
+
|
|
83
|
+
A replacement for each generic pattern, each marked for this platform:
|
|
84
|
+
|
|
85
|
+
| Generic pattern | Upgrade | On this platform |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| A static headline | **Variable-font animation** on `font-variation-settings`, on the state curve | CSS-only, where the pack's face is variable |
|
|
88
|
+
| A fade-in title | **Text-mask reveal**: a clip-path wipe on the entrance curve | CSS-only; a gradient mask is banned where the world bans gradient text |
|
|
89
|
+
| A symmetric grid | **The broken grid**: asymmetric spans, one tile past the container by a gutter, zero empty cells | CSS-only |
|
|
90
|
+
| A card row | **The parallax card stack**: sticky panels in a tall band, each one step lower | CSS-only (`position: sticky`) |
|
|
91
|
+
| Linear easing | **Spring-like motion**: the world's entrance curve, a little overshoot where the world names none | CSS-only; no spring library |
|
|
92
|
+
| A flat overlay | **True layered glass**: the world's glass tokens, blur only on a fixed layer | CSS-only |
|
|
93
|
+
| A hover border | **Spotlight border** following the pointer | **Not available** (needs pointer tracking in script); use a hairline that lights to the accent on hover |
|
|
94
|
+
| A grey drop shadow | **Tinted shadow**: `color-mix(in srgb, var(--ink) 20%, transparent)` | CSS-only, where the world has a shadow |
|
|
95
|
+
| A flat ground | **Grain** on a fixed pointer-inert pseudo-element | Only where the world has that material |
|
|
96
|
+
| An empty hero | **The plate**: the world's hero object by token, or the air | Hero plates and hero objects only; never a generated image as a step |
|
|
97
|
+
|
|
98
|
+
## The fix order (impact per risk)
|
|
99
|
+
|
|
100
|
+
Apply in this order, one group per commit, and stop when the audit list is empty:
|
|
101
|
+
|
|
102
|
+
1. **Fonts**: the pack's two stacks through the world's roles; `font-display: swap` with a sized fallback.
|
|
103
|
+
2. **Palette cleanup**: every literal becomes a `var()` or a `color-mix()` of the fifteen; the dark twin written twice; no page `:root`; the accent spent only on the pressable and the live. A page that "needs a different palette" needs a look: render it under one from `modules/ui-design/styles/` with `--style <name>` on the kit to compare, and leave adopting it to the owner's `config/branding.json`; a redesign never carries a private palette.
|
|
104
|
+
3. **Hover, press and focus states**: the state curve, the world's ring, the 24px floor on every control.
|
|
105
|
+
4. **Layout and spacing**: the world's rhythm, the container, the breakpoint, the radius tier.
|
|
106
|
+
5. **Component replacement**: the world's components for the page's generic ones (its bar, its door, its ledger rows, its card).
|
|
107
|
+
6. **Loading, empty and error states**: designed, named in the states file, rendered.
|
|
108
|
+
7. **Typographic polish**: tracking, measure, tabular figures, balanced headings.
|
|
109
|
+
|
|
110
|
+
## Hard rules
|
|
111
|
+
|
|
112
|
+
- **Keep the existing stack. Never migrate frameworks.** A redesign that changes the build tool is a different task and an ADR.
|
|
113
|
+
- **Do not break functionality.** `node modules/ui-design/kit/probe.js --page <path>` is PASS before the first commit and after the last; a probe that was green and goes red reverts the group that broke it.
|
|
114
|
+
- **Check the dependency manifest and the styling-library version before adding anything**, and adding is a task decision: print the command in the ship notes, do not run it inside a taste pass.
|
|
115
|
+
- **Small, reviewable diffs**: one audit group per commit, each naming its rows. The grader reads the real diff.
|
|
116
|
+
- **The world wins.** An audit row the instance's `DESIGN.md` calls for by name is not a defect; say so in the notes and move on.
|
|
117
|
+
|
|
118
|
+
## Proof
|
|
119
|
+
|
|
120
|
+
The before and after shots from the same states file, side by side, in the modes the page serves and at 1440 / 390 / 320; `render.js` ALL CLEAN after; `probe.js` PASS before and after; the contrast pairs measured; the audit list in the ship notes with every closed row struck and every world-sanctioned row marked as such.
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.462",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.462",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.462",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|