Skip to content

feat(mascot): rework grok's hover and click motion - #126

Merged
RealZST merged 4 commits into
mainfrom
chore/grok-mascot-motion
Aug 28, 2026
Merged

feat(mascot): rework grok's hover and click motion#126
RealZST merged 4 commits into
mainfrom
chore/grok-mascot-motion

Conversation

@RealZST

@RealZST RealZST commented Aug 28, 2026

Copy link
Copy Markdown
Owner

Reworks the Grok mascot's motion, plus two bits of cleanup found on the way.

Motion

The mark is ambiguous β€” it reads as a star with something going round it, and equally as the spinning top it resembles. The two states each take one reading, and share no motion on purpose: a small preview of the spin on hover would spend the click in advance.

Hover. The star holds still and a planet crosses it on a drawn elliptical trajectory whose dashes flow along the path. The planet is a grey four-point flare inside a halo, scaled and faded along the orbit so the near point is large and bright and the far one small and dim. Grey rather than the mark's own colour, so it reads as a second, lesser body rather than a chip off the star.

Drawing the trajectory is what makes the orbit legible. Everything in the mascot is one currentColor, so the planet is swallowed wherever it crosses the mark and there is no drawing it in front. Without the path that reads as a blink; with it the dashes carry on where the planet went, so it reads as passing behind.

The star has to hold still for a second reason: the click stands the mark up from 0deg, so any idle rotation would be mid-turn when a click began and the mark would snap back to 0 to start.

Click. It crouches, hops, and is stood upright -45deg into the ascent, then turns about the vertical axis as it lands and runs down to a stop before unwinding back to brand angle.

-45deg is measured, not chosen: the line through the two spikes sits at exactly that angle, so it stands the mark on its tail with the ring square to the vertical. +45deg lays it on its side instead, and +135deg is pixel-identical to -45deg because the glyph maps onto itself under a half turn.

The three tracks sit on three nested elements, one job per layer:

layer hover click
wrapper β€” the hop, and the squash on touchdown
<svg> β€” the spin
<path> β€” stood upright, then unwound
<circle>/<ellipse> the orbit cut

The nesting is load-bearing rather than tidiness. A child's transform composes before its parent's, so putting the upright rotation on the path and the spin on the svg spins an upright mark; either one on an ancestor of the other, or both on one element in the other order, tilts the axis it spins about by 45 degrees instead.

CLICK_DURATIONS.grok goes from 900ms to 2100ms. The old value pulled is-clicked while the mark was still held at 45deg, cutting the unwind.

Everything the orbit adds is transparent at rest, so the extension tables, the marketplace and the kit drawer are unchanged β€” only agent-card.tsx passes animated, and it already leaves grok on overflow-visible for the orbit to overhang.

Cleanup

Screenshots. The three PNGs under media/pr-grok-build/ only ever illustrated #125. Nothing in the repo references them, and that PR's body points at raw.githubusercontent.com on the contributor's fork rather than at this repository, so removing them here leaves the thread's images intact.

Dead cursor CSS. .shadow-el has no element behind it β€” cursor-mascot.tsx renders only .rocker and .icon-svg. Four rules and two keyframe blocks have been styling nothing since the shadow was dropped from the markup.

Biome. npm run lint was reporting on three files this branch does not otherwise touch. CI runs test and build but not lint, which is why they went unnoticed. Last commit, separable.

Checks

npm test 307 passing, npm run build clean, npm run lint now clean.

RealZST and others added 4 commits August 28, 2026 20:32
The three PNGs under media/pr-grok-build/ only ever illustrated PR #125.
Nothing in the repo references them, and that PR's body points at
raw.githubusercontent.com on the contributor's fork rather than at this
repository, so removing them here leaves the thread's images intact.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015weU8hXkgz73A96UcHL7oS
.shadow-el has no element behind it β€” cursor-mascot.tsx renders only
.rocker and .icon-svg. The four rules and the two keyframe blocks that
drove it were left behind when the shadow was dropped from the markup, so
they have been styling nothing since.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015weU8hXkgz73A96UcHL7oS
Hover no longer scales the whole mark. The glyph reads as a star, so it
holds still while a planet crosses it on a drawn elliptical trajectory
whose dashes flow along the path. The planet is a grey four-point flare
inside a halo, scaled and faded along the orbit so the near point is
large and bright and the far one small and dim β€” grey rather than the
mark's own colour so it reads as a second, lesser body rather than a chip
off the star.

Click reads the same glyph the other way, as the spinning top it also
looks like. It crouches, hops, and is stood upright 45deg into the ascent
β€” the angle the line through its two spikes already sits at β€” then turns
about the vertical axis as it lands and runs down to a stop before
unwinding back to brand angle. The three tracks sit on three nested
elements because a child's transform composes before its parent's, and
that is the only arrangement which spins an upright mark rather than
tilting the axis it spins about.

CLICK_DURATIONS.grok goes from 900ms to 2100ms. The old value pulled
is-clicked while the mark was still held at 45deg, cutting the unwind.

Everything the orbit adds is transparent at rest, so every surface that
draws the mascot without hover β€” the extension tables, the marketplace,
the kit drawer β€” is unchanged. Only agent-card.tsx passes `animated`,
and it already leaves grok on overflow-visible for the orbit to overhang.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015weU8hXkgz73A96UcHL7oS
`npm run lint` has been reporting on three files that nothing in this
branch touched: an unsorted import in agent-mascot.tsx, a stale format in
agent-card.tsx, and a non-null assertion in the memory-grouping test. CI
runs test and build but not lint, which is why they went unnoticed.

The first two are biome's own fixes. The third replaces the assertion
with an explicit throw, so a missing group fails with a message naming
the group rather than with a null dereference three lines later.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015weU8hXkgz73A96UcHL7oS
@RealZST
RealZST merged commit 6a97f99 into main Aug 28, 2026
3 checks passed
@RealZST
RealZST deleted the chore/grok-mascot-motion branch August 28, 2026 12:54
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