Skip to content

fix(website): restore the works-with ribbon and subhead highlight; retime the hero walkthrough - #999

Merged
blove merged 5 commits into
mainfrom
blove/homepage-polish-2
Sep 4, 2026
Merged

fix(website): restore the works-with ribbon and subhead highlight; retime the hero walkthrough#999
blove merged 5 commits into
mainfrom
blove/homepage-polish-2

Conversation

@blove

@blove blove commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Four changes from reviewing the live homepage.

Restored: the flat "Works with" ribbon

The rebuild replaced it with three labelled compatibility groups; the flat strip reads better, so it is back, along with its spec and CSS. The group markup, COMPAT_GROUPS and six now-unused rules are gone, and the only consumer needing cleanup was the spec.

The accuracy guard from the group version was carried forward rather than dropped: the spec still asserts every logo is alt="" aria-hidden beside a visible name and that the strip never reads as customer proof.

One tradeoff to name. The three-group version encoded a distinction the flat line cannot: OpenAI, Anthropic, Gemini and Bedrock sit behind your backend, only LangGraph and AG-UI have direct adapters, and CrewAI and Mastra are reachable through AG-UI. On one undifferentiated row a reader can infer "Threadplane integrates with OpenAI", which is not what ships. "Works with" keeps it a compatibility claim rather than a customer claim, and the parity section and FAQ still make the boundary argument, but that argument now leans on the hero subhead and the proof band.

Restored: the highlighted phrase in the hero subhead

.marker-highlight is back on one phrase, Your backend stays where it is. — the boundary claim, and the sentence worth retaining. One mark, not two: in a sentence this short a second mark reads as decoration and cancels the emphasis.

HERO_SUBHEAD stays the single source. A new HERO_SUBHEAD_SEGMENTS carries the highlight, and a drift guard asserts the segments join back to the string exactly and that exactly one is highlighted. Both guards are mutation-tested.

box-decoration-break: clone alone was not enough on the centered hero — the highlight wrapped mid-phrase at 1440 and orphaned a lone "Your" at 768. A hero-scoped inline-block fixes it, with max-width: 100% so it still wraps inside the measure at 320.

Retimed: the walkthrough

Typing was teaching a developer what typing looks like, while the approval beat was too fast to read.

Beat Before After
First prompt typing 7,640ms 1,820ms
Second prompt typing 4,720ms 1,120ms
Approval panel on screen before the cursor moves 660ms 4,680ms
Hold on the rendered form 8,890ms 5,869ms
Total loop 27,645ms 23,365ms

Typing fell from 45% of the loop to 13%, and that time went to the beat carrying the product's central claim: the agent is blocked, waiting for a human. The pause is the message. All pacing now lives in one commented block in hero-script.ts, each constant arguing its communication job; READ_PAUSE_MS is deleted, so reduced motion loses the animation but keeps every beat. The dwell records that it is calibrated to the current ~60-word proposal and must grow if that copy does.

Removing the dwell turns 5 of 14 script tests red. A spec holds the dwell open on a promise it resolves by hand, proving the cursor is blocked behind it rather than merely ordered after it.

Also: a test that was breaking its neighbours

The new typing test asserted performance.now() elapsed under 2000ms on real timers. It flaked under load and added real seconds to the suite, which knocked over the neighbouring router specs — reported as pre-existing flakes, but clean main runs 179/179 while this branch failed 2 to 3 per run. Fake timers pin the same cadence deterministically; three consecutive runs are 184/184.

One genuinely pre-existing sensitivity remains, confirmed on clean main: demo-shell.component.spec.ts > preserves query params on thread switch fails when both suites run in parallel on a loaded machine. Not touched here.

Verification

Website and demo suites green run alone, 0 lint errors, clean type-check, green production builds. Per-beat timings measured in a real browser over four consecutive loops, variance under 90ms. Hero and ribbon screenshotted at 1440, 768, 390 and 320.

🤖 Generated with Claude Code

blove and others added 5 commits September 4, 2026 13:33
…approval

The playback taught the wrong things. Typing at 40ms/char spent 12.4s of a
27.8s loop showing a prospective customer what a keyboard is, while the beat
that carries the whole product claim — the agent stopping itself to ask a
human before deleting database backups — got 660ms, just long enough for the
cursor to glide over and click Accept. Approving that fast says the gate is a
formality.

Pacing is now one named model in hero-script.ts, each constant carrying the
communication reason rather than the number: TYPE_DELAY_MS 40 → 9,
HOLD_AFTER_TYPING_MS 1200 (new: finish reading the prompt before it is
answered), INTERRUPT_DWELL_MS 4000 (new: the pause IS the message),
HOLD_AFTER_ANSWER_MS 400 → 2000, CURSOR_MOVE_MS and HOLD_AFTER_DONE_MS
unchanged. The component imports the two it enacts instead of keeping copies.

READ_PAUSE_MS is gone. It was a reduced-motion-only stopgap for exactly the
hold that is now HOLD_AFTER_TYPING_MS, and the runner no longer branches on
reducedMotion at all: reduced motion removes animation inside the host, never
a beat, so both audiences follow the same walkthrough at the same tempo.

Measured on /hero over four consecutive loops, before → after: prompt-1
typing 7.64s → 1.82s, prompt-2 typing 4.72s → 1.12s, panel-attached to
Accept-pressed 0.66s → 4.66s, full loop 27.6s → 26.4s.

WAIT_TIMEOUT_MS stays at 30s: it budgets waiting for a CONDITION, not the
length of a pass, and none of these holds run inside a waitFor().

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The homepage rebuild replaced the flat "Works with" recognition line with
three labelled compatibility groups. Roll that back to the pre-rebuild
strip: one flex line, a "Works with" label, eight named logos and a
"+ 4 more" count.

Deletes COMPAT_GROUPS, the three-group markup, and the group-only CSS
(.logo-ribbon-heading / -lede / -groups / -group / -group-head / -note).
Nothing else in the app consumed them — no e2e spec and no style
contract referenced the group markup.

Keeps the accuracy guard the group version introduced: the restored spec
still asserts every logo is alt="" aria-hidden beside a visible name, and
that no "trusted by" / "customers" wording appears. "Works with" is a
compatibility claim, not a customer claim.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The old hero marker-highlighted a key phrase; the rebuild dropped it.
Bring it back on exactly one phrase — "Your backend stays where it is."
— the boundary claim and the sentence a reader most needs to retain. A
second highlight in a sentence this short reads as decoration and
cancels the emphasis.

HERO_SUBHEAD stays the single source of truth. HERO_SUBHEAD_SEGMENTS
sits beside it and carries the split; positioning.spec.ts asserts the
segments join back to HERO_SUBHEAD character for character and that
exactly one is highlighted, so the two cannot drift. Hero.spec.tsx keeps
its .hero-subhead textContent assertion and gains one on the span.

CSS: the new hero is centered, and the phrase wrapped mid-claim —
measured at 768px it orphaned a lone "Your" in its own pill at the end
of line 1, and at 1440px it split into two staggered boxes. Scoped
inline-block makes the phrase wrap as one unit so it drops whole onto
its own line at 1440/1024/768/390; max-width: 100% is the safety valve
that keeps it wrapping inside the measure at 320px instead of
overflowing. box-decoration-break: clone on the base rule is now under a
style contract — without it a wrapped highlight paints one union box
across the lines, which still renders, just wrongly.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… is calibrated to

With typing retimed, HOLD_AFTER_DONE_MS was the longest beat in the loop —
8.9s of a form that has stopped changing, a third of the runtime, and the
likeliest place for a viewer to leave before seeing a whole cycle. Seeing a
whole cycle is the only thing the loop is for, so 8000 → 5000.

Measured over four consecutive loops: form → restart 8.89s → 5.87s, full loop
26.4s → 23.4s. Every other beat is byte-identical to the previous commit —
prompt-1 typing 1.82s, the 1.2s read holds, the 4.66s panel-to-Accept dwell,
and the 2s post-answer hold are all untouched.

Also records the coupling nobody would guess from the number alone:
INTERRUPT_DWELL_MS is calibrated to the ~60-word request_approval proposal in
public/hero-replay.json. Four seconds skims that copy; if the copy grows and
the dwell does not, a reader can no longer get through the proposal and the
beat silently stops doing its job.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… budget

The new typing test asserted `performance.now()` elapsed under 2000ms on real
timers. It flaked under load and added real seconds to the suite, which
destabilised the neighbouring demo-shell router specs — those were reported as
pre-existing flakes, but clean main runs 179/179 and this branch failed 2-3
tests per run. Advancing fake timers pins the same cadence deterministically.
Three consecutive runs: 184/184.

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

vercel Bot commented Sep 4, 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 4, 2026 9:01pm UTC

Request Review

@blove
blove enabled auto-merge (squash) September 4, 2026 20:58

@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.

@github-actions

github-actions Bot commented Sep 4, 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 d932a48 into main Sep 4, 2026
39 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