Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,15 @@ component's.
| `--dur` | 220ms | dialogs, view transitions, step changes |
| `--dur-slow` | 480ms | rails fading, timelines |
| `--dur-draw` | 1200ms | a path drawing in |
| `--dur-message` | 300ms | an explorer message drawing in |
| `--stagger` | 40ms | the gap between rails that light up one after another |
| `--dur-step` | 2500ms | one step of the explorer scene (not zeroed: under reduced motion the scene never plays) |

Under `prefers-reduced-motion: reduce` every duration is 0ms, the cross-document view transition
is off, and every keyframe animation sits inside `@media (prefers-reduced-motion: no-preference)`
so it never runs. Islands ask `reducedMotion()` from `src/lib/motion.ts` and skip timers, smooth
scrolling and autoplay when it is true.
scrolling and autoplay when it is true, and read durations from these tokens through
`durationToken()` rather than keeping their own.

### Motion catalogue

Expand All @@ -240,9 +244,9 @@ package of the redesign that builds it. Anything not in this table does not anim
| M2 | Home → `/mcp/`, `/standards/` → spec, `/explorer/` → scenario | Shared `view-transition-name` on the data view (matrix plate from `MatrixThumb.astro` as `matrix`, map; on the explorer, the scenario title into the page h1) so it morphs instead of crossfading | "this is the same object, larger" | none | WP3, WP5, WP6 |
| M3 | Home facts, server page facts (`Facts.astro`) | Count-up from 0 to the value, 600ms, once, when 50% in view, tabular figures | "these are live numbers" | value rendered at once | WP3 |
| M4 | Standards map, decorative plate | Highlighted path draws in (`stroke-dashoffset`), 1200ms, halo fades after, once on load | "follow this path" | path shown complete | WP5, WP8 |
| M5 | Explorer chain | The current step's arrow draws in (300ms), the body fades up 8px (220ms); later steps dim once stepping starts | "you are here" | arrow and body shown, dimming applied without transition | WP6 |
| M6 | Explorer chain | Optional play: steps advance every 2.5 s after the reader presses Play; any click, key or scroll pauses; never starts by itself | guided reading | Play button hidden | WP6 |
| M7 | Explorer token view | On step change, claims that differ from the previous hop get a 2px `--signal` rail that fades to `--rule` over 480ms | "this is what changed in the token" | rail shown without fade | WP6 |
| M5 | Explorer chain | Per step: the sender and receiver light up in the actor head, the current arrow draws in (300ms, ease-out), the body fades up 8px (220ms); earlier steps keep a quieter arrow and later ones a hairline, in colour, not opacity, so text keeps its contrast | "you are here" | arrow and body shown, highlight and dimming applied without transition | WP6, R-08 |
| M6 | Explorer chain | One scene clock (a Web Animations API timeline) holds the playhead; Play, Pause, Previous, Next, the scrub bar, a click on a step or a log line and the arrow keys all move it. Steps advance every 2.5 s. Auto-advance (amended by review follow-up 8): armed once per page, it starts when the chain has sat in view for 1 s with no input, and stops for good on hover, touch, focus, scroll or any key; it never restarts by itself and never starts with a step in the URL. Play, once pressed, pauses on any click, key or scroll | guided reading | Play button hidden, no auto-advance; the scrub bar and the step buttons still seek | WP6, R-08 |
| M7 | Explorer token view | On step change, claims that differ from the previous hop get a 2px `--signal` rail that fades to `--rule` over 480ms, starting when the message has drawn (300ms) and 40ms apart | "this is what changed in the token" | rail shown without fade | WP6, R-08 |
| M8 | Explorer toggle pages | Changed and removed steps get their rail in the toggle's ink on page load, from transparent over 480ms (one pass, staggered 40ms per step, max 400ms total) | "the toggle touched these" | shown at once | WP6 |
| M9 | Matrix | Row and column crosshair on hover/focus of a cell (`--signal-soft` background, 120ms) | orientation in a large grid | instant | WP4 |
| M10 | Matrix | Cell dialog: backdrop fades, panel moves up 8px, 220ms, using `@starting-style` | "a detail opened" | appears | WP4 |
Expand All @@ -252,6 +256,8 @@ package of the redesign that builds it. Anything not in this table does not anim
| M14 | Long-form pages (`Document.astro`) | Reading progress bar, 2px `--signal`, `animation-timeline: scroll(root)` behind `@supports` | place in the text | hidden | WP2 |
| M15 | Controls | Colour and border transitions on hover/focus, 120ms | affordance | instant | WP2 |
| M16 | Theme toggle | Icon swap only; no rotation | n/a | n/a | WP2 |
| M17 | Explorer toggles | A toggle link swaps the chain in place (crumbs, toggles, notice, steps) through a same-document view transition, 220ms; steps the two chains share morph, the rest fade, and M8 runs on the new rails. The toggle stays its own static page for a reload, a new tab or no JS | "the same chain, with one thing changed" | ordinary navigation | R-08 |
| M18 | Explorer chain | A quiet decision log under the chain gains one line per step reached (number, sender → receiver, message), the newest fading in over 220ms; a line seeks back to its step | "what has happened so far" | lines appear | R-08 |

Removed from the site by the redesign: the pulsing dot in the work-in-progress banner (it loops),
the hover lifts on cards, buttons and the hero thumbnail, the rotating theme toggle, the ambient
Expand Down
8 changes: 5 additions & 3 deletions specs/016-visual-redesign/plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,9 @@ package that builds it. Anything not in this table does not animate.
| M2 | Home → `/mcp/`, `/standards/` → spec, `/explorer/` → scenario | Shared `view-transition-name` on the data view (matrix plate, map, chain head) so it morphs instead of crossfading | "this is the same object, larger" | none | WP3, WP5, WP6 |
| M3 | Home facts, server page facts | Count-up from 0 to the value, 600ms, once, when 50% in view, tabular figures | "these are live numbers" | value rendered at once | WP3 |
| M4 | Standards map, decorative plate | Highlighted path draws in (`stroke-dashoffset`), 1200ms, halo fades after, once on load | "follow this path" | path shown complete | WP5, WP8 |
| M5 | Explorer chain | The current step's arrow draws in (300ms), the body fades up 8px (220ms); later steps dim once stepping starts | "you are here" | arrow and body shown, dimming applied without transition | WP6 |
| M6 | Explorer chain | Optional play: steps advance every 2.5 s after the reader presses Play; any click, key or scroll pauses; never starts by itself | guided reading | Play button hidden | WP6 |
| M7 | Explorer token view | On step change, claims that differ from the previous hop get a 2px `--signal` rail that fades to `--rule` over 480ms | "this is what changed in the token" | rail shown without fade | WP6 |
| M5 | Explorer chain | Per step: the sender and receiver light up in the actor head, the current arrow draws in (300ms, ease-out), the body fades up 8px (220ms); earlier steps keep a quieter arrow and later ones a hairline, in colour, not opacity, so text keeps its contrast | "you are here" | arrow and body shown, highlight and dimming applied without transition | WP6, R-08 |
| M6 | Explorer chain | One scene clock (a Web Animations API timeline) holds the playhead; Play, Pause, Previous, Next, the scrub bar, a click on a step or a log line and the arrow keys all move it. Steps advance every 2.5 s. Auto-advance (amended by review follow-up 8): armed once per page, it starts when the chain has sat in view for 1 s with no input, and stops for good on hover, touch, focus, scroll or any key; it never restarts by itself and never starts with a step in the URL. Play, once pressed, pauses on any click, key or scroll | guided reading | Play button hidden, no auto-advance; the scrub bar and the step buttons still seek | WP6, R-08 |
| M7 | Explorer token view | On step change, claims that differ from the previous hop get a 2px `--signal` rail that fades to `--rule` over 480ms, starting when the message has drawn (300ms) and 40ms apart | "this is what changed in the token" | rail shown without fade | WP6, R-08 |
| M8 | Explorer toggle pages | Changed and removed steps get the same rail treatment on page load (one pass, staggered 40ms per step, max 400ms total) | "the toggle touched these" | shown at once | WP6 |
| M9 | Matrix | Row and column crosshair on hover/focus of a cell (`--signal-soft` background, 120ms) | orientation in a large grid | instant | WP4 |
| M10 | Matrix | Cell dialog: backdrop fades, panel moves up 8px, 220ms, using `@starting-style` | "a detail opened" | appears | WP4 |
Expand All @@ -215,6 +215,8 @@ package that builds it. Anything not in this table does not animate.
| M14 | Long-form pages (`Document.astro`) | Reading progress bar, 2px `--signal`, `animation-timeline: scroll(root)` behind `@supports` | place in the text | hidden | WP2 |
| M15 | Controls | Colour and border transitions on hover/focus, 120ms | affordance | instant | WP2 |
| M16 | Theme toggle | Icon swap only; no rotation | — | — | WP2 |
| M17 | Explorer toggles | A toggle link swaps the chain in place (crumbs, toggles, notice, steps) through a same-document view transition, 220ms; steps the two chains share morph, the rest fade, and M8 runs on the new rails. The toggle stays its own static page for a reload, a new tab or no JS | "the same chain, with one thing changed" | ordinary navigation | R-08 |
| M18 | Explorer chain | A quiet decision log under the chain gains one line per step reached (number, sender → receiver, message), the newest fading in over 220ms; a line seeks back to its step | "what has happened so far" | lines appear | R-08 |

Explicitly removed from today's site: the pulsing dot in the work-in-progress banner (it loops),
the hover lifts on cards, buttons and the hero thumbnail, the rotating theme toggle, the ambient
Expand Down
1 change: 1 addition & 0 deletions specs/016-visual-redesign/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,4 @@ Items from the redesign review, one pull request each, in order.
- [x] R-05 Matrix on phones: below 40rem the matrix is read one way at a time instead of the desktop table squeezed. A row of plain anchors (All and one per requirement group, with counts) picks the view through `:target`, so it works without JavaScript and every group stays in the HTML; the island turns the choice into `data-view` with `aria-current`, so switching keeps the scroll and adds no history entry. "All" draws every requirement as a strip of small glyphs per server, sized from the column with container units, so the whole atlas fits without sideways scroll; its glyphs are a picture and a group's view opens them. A group shows its own columns (one generated `nth-child` range each) with two-line horizontal labels instead of `vertical-rl`, two and a half columns in view so the next one peeks in, and scroll shadows at the frame edges. The server column is 7rem, names wrap to two lines and link to the server page, the transposed view. Desktop is unchanged. Baselines through the `refresh-screenshots` label
- [x] R-06 Matrix on desktop: the table comes straight after the head, and the status key and the live count sit under it. "Filter and group" folds into one quiet button at the end of the head's meta line; opened, the form runs under the whole line. The revision is named once, in the meta line: the lede says "the MCP Authorization specification", the link to its text is "Specification text", and the published date shows only when it differs from the revision id. On wide screens the table fits the column instead of scrolling past its edge (at 1440 px three groups were hidden behind a clipped "Tra…"): its widths come from the group row, a group whose label is wider than its columns (`data-narrow`, from an estimate of the label's length) takes the label's width, and the other columns share the rest down to a 2.25rem floor, below which the frame scrolls. The island redoes the sums when a filter changes the groups. Phones keep R-05. Baselines through the `refresh-screenshots` label
- [x] R-07 Home figures and copy: the facts read Servers, Requirements, Cells observed and Specifications. "Cells observed" counts the current matrix cells that have an observation, beside the total (611 of 897), in place of the 1,664 entries of the append-only history, which counted every scan of the same cell again; `Facts.astro` takes an optional `of` total that stands still while the figure counts up. "Latest observations" shows the six newest observations of the current revision with one row per requirement and per server, so one scan run no longer fills the panel with six rows of the same feature. The seed-data sentence under the list is gone (the server page and `/contribute/` no longer carried one). No baseline changes: the home screenshot stops above the facts
- [x] R-08 The explorer as a scene: one Web Animations API timeline (a target-less scene clock) holds the playhead for Play, Pause, Previous, Next, a scrub bar in the stepper, the arrow keys, a click on a step and the decision log (M6). Auto-advance starts once the chain has sat in view for 1 s with no input, stops for good on hover, touch, focus, scroll or a key, never restarts and never runs under reduced motion; M6 in the plan is amended. Per step the sender and receiver light up in the actor head, the message draws in over 300ms, earlier steps keep a quieter arrow and later ones a hairline (colour, not opacity, so axe passes while stepping) (M5). The changed claims get their rail 40ms apart once the message lands (M7), now through the Web Animations API instead of an `is-fresh` class. A toggle swaps the chain in place through a same-document view transition of 220ms and pushes its URL; back and forward swap again, the analytics count the swap as a pageview (M17). A quiet log under the chain gains one line per step (M18). Durations come from the motion tokens (`--dur-message`, `--stagger` and `--dur-step` are new) through `durationToken()` in `src/lib/motion.ts`. Baselines through the `refresh-screenshots` label
130 changes: 97 additions & 33 deletions src/components/ChainPage.astro
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ function arrow(from: string, to: string) {
class:list={["step", { "is-toggled": s.toggled && !s.removed, "is-removed": s.removed }]}
data-step={s.id}
data-index={s.index}
data-from={s.from}
data-to={s.to}
data-toggled={s.toggled && !s.removed ? "" : undefined}
data-removed={s.removed ? "" : undefined}
data-replaces={s.replaces}
Expand Down Expand Up @@ -390,8 +392,8 @@ function arrow(from: string, to: string) {
grid-template-columns: var(--lanes-w) var(--body-w);
border-top: 1px solid var(--rule);
border-left: 2px solid transparent;
scroll-margin-top: calc(var(--header-h) + 5rem);
transition: opacity var(--dur) var(--ease);
scroll-margin-top: calc(var(--header-h) + 6rem);
transition: background-color var(--dur-fast) var(--ease);
}
.step:first-child {
border-top: 0;
Expand Down Expand Up @@ -580,7 +582,22 @@ function arrow(from: string, to: string) {
color: var(--ink-2);
}

/* step-through, driven by the island: the current step in the signal, later ones dimmed */
/*
* The scene, driven by the island (M5): the sender and receiver light up in the actor head,
* the current step carries the signal on a faint tint, earlier steps keep their arrow in a
* quieter ink and later ones only a hairline. Colour, not opacity, so no text loses contrast.
*/
.actor__name {
padding-bottom: 2px;
border-bottom: 2px solid transparent;
transition:
color var(--dur-fast) var(--ease),
border-color var(--dur-fast) var(--ease);
}
.actor:is(.is-from, .is-to) .actor__name {
color: var(--signal);
border-bottom-color: var(--signal);
}
.step[aria-current="step"] .step__lanes {
color: var(--signal);
}
Expand All @@ -595,50 +612,97 @@ function arrow(from: string, to: string) {
.step[aria-current="step"] .step__body {
border-left-color: var(--signal);
}
.step.is-future {
opacity: 0.45;
.chain__steps[data-stepping] .step[aria-current="step"] {
background: color-mix(in oklch, var(--signal) 5%, transparent);
}
.step.is-past .step__lanes {
color: var(--rule-strong);
}
.step:is(.is-past, .is-future) .step__message {
color: var(--ink-2);
}
.step.is-future .step__lanes {
color: var(--rule);
}

/*
* M5: once the reader steps, the current arrow draws in (300ms) and its body rises 8px
* (220ms). M8: on a toggle page the rails of the touched steps light up once, 40ms apart and
* no later than 400ms. Neither runs under reduced motion; both end where the static page is.
* M8: on a toggle page the rails of the touched steps light up once, 40ms apart and no later
* than 400ms; this also runs on the steps a toggle swaps in (M17). M5 and M7 run in the island
* through the Web Animations API. None of it runs under reduced motion.
*/
@media (prefers-reduced-motion: no-preference) {
.chain__steps[data-stepping] .step[aria-current="step"] .arrow__line {
animation: draw-x 300ms var(--ease-draw) both;
}
.chain__steps[data-stepping] .step[aria-current="step"] .arrow::after,
.chain__steps[data-stepping] .step[aria-current="step"] .arrow-self {
animation: fade-in 300ms var(--ease) both;
}
.chain__steps[data-stepping] .step[aria-current="step"] .step__body > * {
animation: rise var(--dur) var(--ease) both;
}
.step:is([data-toggled], [data-removed]) {
animation: rail-in var(--dur-slow) var(--ease) both;
animation-delay: min(calc(var(--touched, 0) * 40ms), 400ms);
animation-delay: min(calc(var(--touched, 0) * var(--stagger)), 400ms);
}
}
@keyframes draw-x {
@keyframes rail-in {
from {
transform: scaleX(0);
border-left-color: transparent;
}
}
@keyframes fade-in {
from {
opacity: 0;
}

/* M17: the toggle morph, a same-document view transition at the morph duration */
:global(:root.toggle-morph::view-transition-group(*)),
:global(:root.toggle-morph::view-transition-old(*)),
:global(:root.toggle-morph::view-transition-new(*)) {
animation-duration: var(--dur);
animation-timing-function: var(--ease);
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(8px);
}

/* M18: the decision log the island writes under the chain, one quiet line per step */
:global(.chain-log) {
margin-top: var(--space-4);
font-size: var(--tiny);
}
@keyframes rail-in {
from {
border-left-color: transparent;
:global(.chain-log__title) {
margin: 0 0 var(--space-2);
font-size: var(--tiny);
font-weight: 600;
color: var(--ink-2);
}
:global(.chain-log__list) {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 2px;
}
:global(.chain-log__list a) {
display: grid;
grid-template-columns: 2rem minmax(0, 14rem) minmax(0, 1fr);
gap: var(--space-3);
padding: 0.2em 0.5em;
border-left: 2px solid transparent;
color: var(--ink-2);
text-decoration: none;
transition:
color var(--dur-fast) var(--ease),
border-color var(--dur-fast) var(--ease);
}
:global(.chain-log__list a:hover) {
color: var(--ink);
}
:global(.chain-log__list [aria-current] a) {
border-left-color: var(--signal);
color: var(--ink);
}
:global(.chain-log__num) {
font-variant-numeric: tabular-nums;
text-align: right;
}
:global(.chain-log__msg) {
font-family: var(--font-mono);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@media (max-width: 40rem) {
:global(.chain-log__list a) {
grid-template-columns: 1.5rem minmax(0, 1fr);
}
:global(.chain-log__msg) {
grid-column: 2;
}
}

Expand Down
Loading
Loading