Skip to content

feat(website): the compatibility band becomes an airport diagram - #1080

Merged
blove merged 16 commits into
mainfrom
blove/homepage-compatibility-redesign-8ae4db
Sep 9, 2026
Merged

feat(website): the compatibility band becomes an airport diagram#1080
blove merged 16 commits into
mainfrom
blove/homepage-compatibility-redesign-8ae4db

Conversation

@blove

@blove blove commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Summary

The compatibility band was split out of the dark proof band in #1067 and kept the pre-ATC treatment: three hairline-separated groups, twelve integrations as 14px names beside 17px marks, a footer link and a disclaimer. It becomes a full-bleed aviation-yellow FAA-style airport diagram, where the chart vocabulary carries the argument the group labels and the aside paragraph were carrying as prose.

Chart element What it is
Main terminal, solid ink <chat> — Threadplane
Concourse A / B, hatched @threadplane/langgraph / @threadplane/ag-ui
Gates A1, B1–B6 the seven runtimes, each at a white stand
Outside the neat line the five model providers

Two values carry the whole meaning with no legend: white is somebody else's, ink is ours.

Verifying against /docs/choosing-an-adapter shaped the design twice. There are exactly two adapters, not three equal-weight groups. And Threadplane never talks to a model provider at all — the adapters call your LangGraph or AG-UI endpoint — so those five marks moved outside the neat line rather than sitting at integration weight. The wording is deliberately "never talks to them", never "never sees it": never-sees is a data claim the docs do not support, the same shape as the three claims #1067 had to kill.

The yellow ground is load-bearing, not decoration. Every mark here is a dark logo drawn for a light ground (Anthropic #181818, CrewAI and Pydantic #111827, LangGraph #1C3C3C), so on aviation yellow they render bare with no chips — which is exactly why they were invisible on the dark band before the split.

Spec: docs/superpowers/specs/2026-09-08-compatibility-airport-diagram-design.md
Plan: docs/superpowers/plans/2026-09-08-compatibility-airport-diagram.md

What the guards are for

Designing this surfaced four label collisions that only an eye caught — gate numbers over package labels, a taxiway drawn through the main terminal, sub-labels rendering outside a 26px concourse, the scale bar on top of runway 09R. Eyes do not scale, so e2e/home-airport.spec.ts measures every rendered text run and mark against the structure that owns it, in viewBox units.

Review found several assertions that passed vacuously and are now mutation-proven: a gate 120 units outside the viewBox once passed every geometry test; deleting the plate once left 6 of 7 unit tests green; WIDE_RATIO was checked against a value derived from itself and is now tied to bedrock.svg's own viewBox.

Two real defects were caught before shipping. role="presentation" does not inherit to descendants, so the plate leaked runway ids and taxiway letters to screen readers. And display: none on the phone stack would have left the band with no accessible content on desktop, since the provider names live only there — the stack is now visually hidden via the repo's existing .stage-skip clip-path idiom, and style-contracts.spec.ts pins that so a future cleanup cannot silently revert it.

The narrow-viewport breakpoint is 1023px, not the usual 767px, and that is measured: at a 768px viewport the plate scaled to 0.71 and put callsigns at 6.0px.

Test Plan

  • npx nx test website green on the rebased tree
  • npx nx lint website — 0 errors
  • npx playwright test --config=apps/website/playwright.config.ts e2e/home-airport.spec.ts e2e/website.spec.ts — 39 passed, including homepage spine order
  • Browser-verified at 1440px, 900px and 390px: 14 logo requests all 200, zero empty marks, no horizontal scroll, no console errors
  • Desktop stack visually hidden (clip-path), tablet and phone show the gate list, plate hidden

🤖 Generated with Claude Code

@vercel

vercel Bot commented Sep 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
threadplane Ready Ready Preview Sep 9, 2026 2:30am UTC

Request Review

@blove
blove enabled auto-merge (squash) September 9, 2026 02:12
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated approval: this PR received an intelligent (AI) code review. See the review comments on this PR.

blove and others added 16 commits September 8, 2026 19:18
The band keeps the pre-ATC treatment: three hairline-separated groups,
twelve integrations as 14px names beside 17px marks, plus a footer link
and a disclaimer. It becomes a full-bleed aviation-yellow FAA-style
airport diagram, where the chart vocabulary carries the argument that
the group labels and the aside paragraph were carrying as prose.

Verifying against /docs/choosing-an-adapter shaped the design twice:
there are exactly two adapters, not three equal-weight groups; and
Threadplane never talks to a model provider at all, so those five marks
move outside the neat line rather than sitting at integration weight.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Six tasks: the geometry module and its unit spec, the plate, the styles,
the phone form, an in-browser overflow spec, and a verification gate.

The overflow spec is not optional ceremony. Designing this section
surfaced four separate collisions that only an eye caught — gate numbers
over package labels, a taxiway drawn through the main terminal,
sub-labels rendering outside a 26px concourse, and the scale bar on top
of runway 09R. Eyes do not scale.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t it means

Review follow-ups on the geometry module, all naming/derivation/guards — no
coordinate moves except B6's width.

FIELD now actually bounds the drawing. It was decoupled: widening APRON_B past
the viewBox left all 8 tests green, because nothing compared a structure to
FIELD at all. A new test contains MAIN, both concourses, both aprons, both
runways, all three taxiways and every stand's rotated extent.

ROW1/ROW2 are renamed to what they hold: `box` was the stand's centre y
(`standCy`), `name` the callsign's baseline (`labelY`). A new per-row ordering
assertion catches a box slid down onto its own label — a visibly broken plate
that the old suite passed.

CONCOURSES carries the row, the apron and `gatesAbove`, so "A is the up row"
is stated once instead of re-encoded in the spec's local table, in the ROW1/
ROW2 names and again in the component to come. The stub, apron, gate-span and
gate-count tests now loop over it.

B6's width becomes `round(s * WIDE_RATIO)` = 20, not the hand-typed 30 that
was 2.5:1 under a comment stating 1.67. The sizing test now asserts the
property (every gate has s > 0; any `w` is > s and on the ratio) instead of
listing B6 by name, so a second wordmark can join without a red suite.

Also: the apron test uses the stand's true rotated half-extent, since each
stand counter-rotates about its own centre; the margin band (provider row,
scale bar, north arrow) is guarded against the neat line and the view the way
architecture-diagram.spec.ts guards its model strip; PLANE_PATH's duplication
of ui/PlaneMark.tsx is enforced by reading that file rather than asserted in a
comment; `MAIN.x1 < CONC.x0` is strict, since equality means zero-length
connectors; and LINK_A_Y/LINK_B_Y must fall inside both the terminal's and
their concourse's y span.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Task 1's code review renamed ROW.box/ROW.name to standCy/labelY and moved
the row, apron and gates-side pairing onto CONCOURSES, so the component
code in task 2 now loops CONCOURSES instead of restating which row goes
with which concourse.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
WIDE_RATIO had no coverage: B6's `w` was computed as `B6_H * WIDE_RATIO`,
so the spec's `w ~= s * WIDE_RATIO` check compared the constant with itself
and could not fail. Setting WIDE_RATIO to 2.5 left all 12 tests green while
stretching the AWS wordmark at gate B6 and in the provider row.

Write both of B6's numbers as literals like every other value in the table
(the derived B6_H is gone; `w` is still 20), and add a test that reads the
wordmark's own viewBox off disk and holds WIDE_RATIO to it. The literal `w`
makes the ratio check compare two independent values, and the new test pins
the ratio to something outside the module.

Also close the CONCOURSES single-sourcing at the spec boundary: the field
bounds list is built from CONCOURSES instead of naming the boxes by hand,
and LINK_A_Y / LINK_B_Y join the table as `link` so the connector test
stops re-pairing them itself. A third concourse now gets its box, apron and
link checked the moment it is declared.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Code review of task 2 found the band would have had no accessible content
on desktop at all: the plate is decorative and the five provider names live
only in the stack, so display:none removed them from the tree entirely.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…lly tested

review fixes on 474f085f:

- the SVG is aria-hidden, not role="presentation". presentation is not
  inherited, so every <text> on the plate ("09L", "2000 FT") still reached
  the accessibility tree as unnamed chart noise while the provider names,
  which exist only in the HTML stack, were the band's real content.
- the plate had no test at all: swapping <Plate /> for an empty <figure />
  left 6 of 7 specs green. A stand per gate and a concourse per adapter are
  now asserted against the tables.
- the name test is scoped to .airport-stack. Unscoped, getAllByText also
  matched the SVG's own <text>, so deleting the accessible list would have
  left half of it passing. Same for the concourse test, which matched only
  the plate.
- the CTA test asserts the [data-cta] hook; the copy and the href belong to
  AdapterGuideLink.spec.tsx.
- PROVIDERS carries the optional `w` the gate table already has, so the
  component no longer asks whether a filename ends in bedrock.svg to know a
  mark is a wordmark. The spec's two sizing tests walk both tables, which is
  the coverage the margin row never had.
- Row and Runway are exported from the data module instead of derived in the
  component from the two constants that happen to exist today.
- the x tick loop bounds on the frame it decorates, like the y loop.

Two intended one-unit shifts: the Bedrock wordmark is 33 wide rather than
33.4 (its x moves 0.2), and each vertical tick moves 8 units right, from
88..968 to 96..976 — still inside the neat line.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Removing aria-hidden from the SVG passed all 21 tests — the one contract
the previous commit exists to establish was the one with no guard.
role="presentation" does not inherit to descendants, so the plate's own
text leaked to screen readers while the provider names, which live only
in the stack, would have gone missing.

Also starts both graticule loops at the frame they decorate; the x loop
had been moved and the y loop left behind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…form

Replaces the `.compatibility-*` block with the airport-diagram styles: the
plate's airfield, buildings, stands and margin furniture, plus the head,
footer and the CTA rule that `AdapterGuideLink` needs because it replaces its
className rather than appending to it.

The yellow ground is load-bearing rather than decoration — every mark on the
plate is a dark logo drawn for a light ground, which is why they render bare
with no chip. Two values carry the diagram's meaning with no legend: partner
stands are white, the main terminal is ink.

`.airport-stack` is the band's only accessible content: the plate is
aria-hidden and the five model-provider names exist nowhere else. So it is
VISUALLY hidden on desktop with the `.stage-skip` idiom (absolute + 1px +
clip-path) and never `display: none` — taking it out of the tree would leave
the section empty to a screen reader. Under 768px the plate is hidden instead
and the same gate table renders as an HTML list, the `.arch-stack` precedent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The label's knockout plate covers only the line above it, so hatch strokes
ran straight through the glyphs of @threadplane/langgraph. A painted-under
halo cuts the hatch per glyph, which beats widening the plate: the plate is
sized by a font-metric estimate, so anything depending on it breaks silently
when the type changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Designing the compatibility band surfaced four label collisions that only
a human eye caught: gate numbers over package labels, a taxiway drawn
through the main terminal, sub-labels rendering outside a 26px concourse,
and the scale bar on top of runway 09R. Eyes do not scale. This measures
the rendered plate against lib/airport-diagram.ts so the next one fails a
check instead of shipping.

Six checks, each one of those four generalised: concourse type stays
inside the building that names it; the concourse name plate — sized by a
font-metric estimate, so nothing else holds it to reality — actually backs
its label; every mark sits inside its stand; no two text runs on the plate
overlap; no pavement crosses the main terminal; chart furniture and the
off-airport row stay in the margin below the neat line.

Counts come first. Every measurement walks a NodeList, and a walk over an
empty list passes, so an unrendered plate would otherwise report no issues
at all.

Overlap between elements that do not share a coordinate system is the one
comparison that cannot use getBBox directly: the airfield sits at a
heading and each stand counter-rotates about its own centre, so an
axis-aligned bound around tilted type reports collisions that are not
there. Those transform each bbox's four corners into the plate's user
space and separate the quads properly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nx mangles the -- passthrough into 'unknown option --_=<spec>', so both
task 5 steps failed before playwright even started.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…at it claims

Final-review pass over the compatibility airport diagram.

The plate was unreadable between 768px and ~1000px. `.ap-svg` is
`width: 100%`, so the 1000-unit drawing scales with its container: at a
768px viewport that container is ~707px, the plate renders at 0.71, and
callsigns land at 6.0px with gate ids at 5.3px. The HTML gate list now
takes over at `max-width: 1023px` rather than 767px, so tablets get the
readable list instead of a shrunken chart — not a sideways scroll, which
the spec rules out for this band. A new e2e case at 900px proves it, and
fails against the old breakpoint.

Three guards that could not see their own subject:

- The band's whole accessibility rests on `.airport-stack` being hidden
  visually (clip-path) and never with `display: none` — the plate is
  aria-hidden, so the five provider names and the "never talks to them"
  claim exist nowhere else in the DOM. Nothing asserted it. A style
  contract now pins the desktop rule, positively and negatively.
- The "never talks to them" test read `container.textContent` unscoped,
  so the aria-hidden plate satisfied it. Deleting the stack's off-airport
  label left all ten tests green while the claim vanished from the phone
  form. It is scoped to `.airport-stack` now, like its neighbour.
- The off-airport row itself was uncounted, and the e2e's margin check
  walks a NodeList that passes when empty. Deleting the whole provider
  row left both suites green. The counts sit beside the other
  `toHaveCount` assertions.

`MS AGENT FWK` is an abbreviation a 38px stand forces, but it was also
what the phone list and every screen reader got. `Gate.long` carries the
whole name; the plate keeps the short one.

Also: the chart id lost a double space, the spec doc's field extents and
B6 size now match the code, `TPL` is recorded as a real assigned IATA
code the way `AL-0059` was, and four plate fills stop hardcoding
`--color-ink` / `--color-signal` as literals. Every rendered colour is
unchanged — verified in the browser.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@blove
blove force-pushed the blove/homepage-compatibility-redesign-8ae4db branch from 21fe386 to ea9f7cb Compare September 9, 2026 02:18
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@blove
blove merged commit 5fcba51 into main Sep 9, 2026
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant