feat(landing): answer the pointer on the builders' band - #253
feat(landing): answer the pointer on the builders' band#253wondopamine wants to merge 4 commits into
landing): answer the pointer on the builders' band#253Conversation
The band that claims the harness was built for how it feels to use is now the one place on the page that answers your hand: drafting marks bloom on a fixed grid where the pointer passes and unwind behind it over --motion-trail. Ported from the ga-hero-ink reference — same cell grid, same band painted along the path, same accumulate-on-linger and decay-through-a- ramp, same pre-rendered atlas so a frame is blits rather than draws, same occlusion by the words rather than a hole cut around them. One thing is not ported: the reference sets its ramp in ASCII glyphs, and a third typeface in product UI is a TYP-1 finding, so the ramp is drawn in the marks the sheet already uses — construction point, scale division, registration cross, circled crossing, snap handle. It stays decoration by construction. Ink, grid pitch and decay come from tokens or it declines to draw. The alpha ceiling is set where the darkest mark still leaves the band's text above 8:1 on the wash. It never renders on the server, never mounts under prefers-reduced-motion or for a coarse pointer, hides under forced colours, takes no pointer events, and is hidden from assistive technology. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Fixed 4 issues, documented here for shared learning purposes!
Few things to confirm with you:
|
Adds the two contract tests PR #253 claimed as manual-only (the Quick start link stays clickable through the trail, and a touch pointer gets no canvas at all), extracts the prefers-reduced-motion matchMedia check into hooks/use-reduced-motion.ts to stop it being duplicated a third time, and prunes trail cells that fall outside the grid after a resize. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Thanks so much @natashaannn. Your changes about avoiding the duplicated checks (reducing the motion), will it be applied for any follow up works? I wasn't aware of it and not sure my agent will do this again or not haha |
Good question.. It's usually caught in a review. Let me see what I can implement in the code base right now to prevent it! Also feel free to merge this if Reza is ok with it haha. Also @wondopamine this can be resolved by installing the dx harness plugin hehe noticed your claude wasn't using it! |
There was a problem hiding this comment.
ok to merge, but note that will require another deploy to airbase separately. @wondopamine @natashaannn
What this is
The builders' band — the one that says the harness was built for how it feels to use — now answers your hand. Move the pointer across it and drafting marks bloom on a fixed grid where it passes, then unwind and fade behind it. It is the only interactive decoration on the page, and it is on that band because a claim about how something feels is better shown once than asserted twice.
The interaction
Ported from the reference the builder chose (
ga-hero-ink), read rather than guessed at, so the mechanic is theirs: a fixed cell grid, a band painted along the pointer's path, cells that accumulate so a pause saturates a patch while a sweep only tints it, and one decay that unwinds each cell back down a light-to-heavy ramp. A ragged deposit edge keeps the band's outline from reading as machine-drawn. The ramp is pre-drawn into an atlas once per resize, so a frame is N blits rather than N paths, and the loop exists only while marks do — an idle band costs no frames.The words paint over the field rather than clearing a hole in it, which is what the reference does and what makes the field read as depth instead of damage.
The one thing not ported
The reference sets its ramp in ASCII glyphs on a monospace stack. A third typeface in product UI is a TYP-1 (L1) finding, and this site's only mono waiver is written to be confined to the builder's-note postcard. So the ramp is drawn instead, in the marks the sheet already uses:
Same field, the drawing's own vocabulary, and no waiver needed. Say the word if you would rather have the literal ASCII version — that is a small change plus a widened TYP-1 waiver, and it is your call to make.
How it stays decoration
--blueprint-ink), grid pitch (--ground-pitch, quartered, so every fourth mark lands on a division the sheet already draws) and decay (--motion-trail, new) are read at runtime. If any is missing the field declines to draw, because nothing is lost when decoration says no.prefers-reduced-motion(A11Y-5) or for a coarse pointer, hidden underforced-colors: active, no pointer events,aria-hidden(A11Y-6), and no information carried (MOT-3).--motion-trail: 2400msjoins the motion token set. It is a decorative decay, not an interface duration, so MOT-1's 300ms bound governs it no more than it governs the landing reveal — the token comment says so, at the definition, where a reviewer can find it.Related tickets
Relates to #201 (decorative layers are ungoverned). This is a second instance of that class, and it moves one of the three candidates along: the ground layer answered "no graphic behind a glyph" by staying outside every text container, and this one takes the other branch — it passes behind text deliberately, with the contrast contribution measured and stated. Two surfaces now, two different answers, both defensible. Whichever way the control lands, it should cover both. The forced-colours candidate from the same issue is followed here as a habit, and the third (a withdrawal breakpoint) is answered by pointer type rather than width.
Relates to #108 (Design: /) — same surface, same landing run.
Verification
pnpm buildwith its standards, Python and notices gates,typecheck,lint,token-audit,type-scan,a11y-static, 93 unit tests, and 52 end-to-end tests — all pass.Three contract tests are new. One sweeps the pointer across the band, counts painted pixels, and waits for the band to return to blank paper (the decay is a decay, not a state). One asserts the canvas is absent under reduced motion — not paused, not shortened, absent. One asserts it is hidden under forced colours.
Also checked by hand in a browser: the Quick start link stays clickable through the field, a touch device gets no canvas at all, and the trail follows the band correctly after scrolling.
One real bug surfaced while building it, and it is worth knowing about beyond this component: the build minifies
2400msto2.4s, so aparseFloaton a duration token that trusts the authored unit gets2.4. The trail decayed inside a single frame and drew nothing. The token read now checks the unit, and both paths are exercised — dev serves2400ms, the build serves2.4s.🤖 Generated with Claude Code