fix(website): restore the works-with ribbon and subhead highlight; retime the hero walkthrough - #999
Merged
Merged
Conversation
…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>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
blove
enabled auto-merge (squash)
September 4, 2026 20:58
Contributor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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_GROUPSand 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-hiddenbeside 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-highlightis 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_SUBHEADstays the single source. A newHERO_SUBHEAD_SEGMENTScarries 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: clonealone was not enough on the centered hero — the highlight wrapped mid-phrase at 1440 and orphaned a lone "Your" at 768. A hero-scopedinline-blockfixes it, withmax-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.
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_MSis 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 switchfails 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