Concept v6.0.1 — motion
Motion
Ten engine families drive the whole theme rather than per-section bespoke code. The families were never wrong — they were too coarse. Each hides 3–15 distinct components with their own durations and triggers. Every measured value on this page was read from the installed theme on 2026-08-29.
The four corrections — C-0a to C-0d
Applied 2026-08-29 (LAR-1415). The earlier block closed the question where does the theme keep its motion vocabulary. It did not close what does the theme actually run. Four of the numbers we carried were wrong. They are struck rather than silently overwritten, because comps built before this date were drawn against them.
C-0a The reveal is 1.5s, not 600ms; the cascade is 100ms, not 75ms
<animate-element> runs four named variants: fade-in 1.5s,
fade-up 1.5s (translateY(min(2rem,90%))→0), fade-up-large
1.0s (90%), zoom-out 1.3s (scale 1.3→1) — all on
easing [0.16, 1, 0.3, 1], not
cubic-bezier(0,0,0.3,1). It waits for image load and resolves after 500ms.
The grid cascade is a different element, <motion-list>:
desktop translateY(50px), 0.5s, 0.1s stagger; mobile
translateY(30px), 0.3s, 0.05s stagger.
C-0b Count-up is a tenth engine, not part of countdown
<number-counter> animates 0 → value via a Motion.animate
progress callback, duration from data-duration, easing
[0.16, 1, 0.3, 1]. Family 8 covers countdown only and never described
it.
C-0c The button hover is a fill-slide with four states, not a colour swap
<hover-button> is the single most-used element in the theme at
95 call sites. It slides a [data-fill] child
y: 76% → 0% over 0.6s on enter and to y: −76% on leave.
A spec that says only "invert on hover" is describing a different button.
C-0d The installed theme is Concept v6.0.1
Per config/settings_schema.json → theme_info, not the v6.0.0 our
docs pinned. Re-verify any value quoted from a v6.0.0-era read. The 38
settings-backed tokens were extracted 2026-07-13 and re-verified 2026-07-29 — both
v6.0.0-era. They have not been re-read against v6.0.1.
The ten engine families
1 Scroll-reveal on entry
<animate-element>: 1.5s fade-in / 1.5s
fade-up / 1.0s fade-up-large / 1.3s zoom-out, all on
[0.16, 1, 0.3, 1]. Grid cascade is <motion-list>: desktop
50px / 0.5s / 0.1s stagger, mobile 30px / 0.3s / 0.05s stagger. Runs once, disabled under
reduced motion.
2 Scroll-linked continuous
Parallax, scroll-zoom, ambient loops. <parallax-element> is auto-disabled
on matchSmall; <slideshow-parallax> is not —
it runs on mobile too.
3 Hover micro-interactions — a fill-slide, not a colour swap
<hover-button> slides a [data-fill] child y: 76% → 0% over
0.6s on enter and to −76% on leave. <hover-link> (39 uses) and
<hover-element> (14 uses) are the anchor and generic forms of the same
0.6s slide.
Design all four states: rest → hover (fill-slide in) → leave (fill-slide
out) → busy (aria-busy="true": text fades out over 0.15s,
loader dots pulse scale(1.6 ↔ 0.6) at 0.35s with 0.175s stagger, infinite
alternate).
Also in this family: card second-image crossfade with 1.1× zoom at 300ms, the quick-add
reveal, and 3D lift rotate 1° with shimmer. No vertical lift. LAR-876
established across all 354 theme files that of the 17 card :hover rules in
theme.css, none moves the card — that law is unchanged by this correction.
4 Looping tickers
Marquee, announcement bar. <marquee-element> computes its own loop:
--duration = (33 − speed) × min(2.5, ceil(width / parentWidth)) seconds. It is
computed at runtime, so --duration-marquee: 1.5s does not
describe it.
5 Carousels
Autoplay, pause on hover, clickable pagination. <control-button> is the
pause control and is an accessibility floor, not an option.
6 Overlay enter/exit
Drawers slide from the edge, popups rise translateY 100% → 0 at 300ms.
<modal-element> adds active after a 75ms delay and waits for
CSS transitionend; <x-modal> and
<drawer-element> dismiss on a 30% drag.
7 Text reveal
Per-character, backing the highlight system. The mechanism is
<split-words> (Splitting.js, 30ms per-word stagger) wrapping each word in
an <animate-element>, with <highlighted-text> adding
animated once the split resolves.
8 Countdown
<countdown-timer> re-renders days/hours/mins/secs on a 1000ms
setInterval and hides on expiry. It carries no animation — it
is a text re-render, not a motion engine.
9 Sticky chrome
Header hide-on-down / reveal-on-up, mobile dock, sticky add-to-cart.
<sticky-header> thresholds: header-scrolled at
headerHeight + 10px, header-nav-scrolled at
2 × headerHeight, header-hidden past
headerBottom + 100px on scroll-down. Draw all three states.
10 Count-up NEW
Added 2026-08-29, LAR-1415 (C-0b). <number-counter> animates 0 → target,
duration from data-duration, easing [0.16, 1, 0.3, 1]. Separate
engine from family 8. Server-render the final number as real text; the
count-up is decoration.
Every one has a reduced-motion fallback. Decorative motion layers are
aria-hidden and never take focus.
Native motion + block inventory
Every component below is stock Concept. Zero development. They are documented because LAR-1415 found that 98 of the theme's 116 registered interactive elements were named in no document we hold — a designer working from "nine engine families" could not know these exist, and a build cannot wire a component whose element name is not written down.
Global laws that bind every entry. Inter throughout ·
#171717 / #ffffff / #ffddbf / #e11d48 ·
flat cards, no border, 10% shadow · pill buttons, zero shadow, invert on hover ·
NO vertical card-lift (LAR-876) · server-render all load-bearing text ·
every motion needs a reduced-motion fallback · decorative motion is aria-hidden
and never focusable.
Count reconciliation — read this before citing a number
LAR-1415's headline is "24 usable candidates". Addendum C as written does not decompose to 24 in one obvious way, so the arithmetic is stated rather than asserted.
| Basis | Count |
|---|---|
| Addendum C § 1 register lines (motion) | 16 |
| Addendum C § 2 register lines (blocks) | 5 |
| § 1 + § 2 register lines | 21 |
| Distinct JS elements named across § 1 | 22 |
| Distinct theme blocks named across § 2 | 7 |
| Distinct native items, § 1 + § 2 | 29 |
| § 1 lines (16) + § B blocks (6) + § E settings (2) — the only decomposition that lands on 24 | 24 |
CANNOT-VERIFY: which decomposition LAR-1415 intended by "24". The last row is the only one that reaches 24 exactly, but LAR-1415 does not state it. All 21 register lines / 29 distinct items are documented — the superset — so no candidate is lost to the ambiguity. Cite "21 register entries covering 29 distinct native items", not "24", until LAR-1415's author reconciles it.
§ 1 — Native motion components (16 entries, 22 distinct elements)
| Element | Role | Measured timings | Key constraint | Tier |
|---|---|---|---|---|
| <motion-list> theme.js:4099 |
Grid cascade | Desktop 50px / 0.5s / 0.1s stagger; mobile 30px / 0.3s / 0.05s | Runs once. Re-fired by <tabs-element>. Supersedes the 75ms --stagger-step. |
MUST |
| <hover-button> <hover-link> <magnet-link> |
CTA treatment | Slide 0.6s. Busy: text 0.15s, dots scale(1.6↔0.6) 0.35s, 0.175s stagger. Magnet spring 1.5s. |
Design all four states: rest / hover / leave / busy. Magnet desktop-only. Gated by buttons_hover. |
MUST |
| <control-button> theme.js:7716 |
Carousel pause | — | Accessibility floor — an autoplaying rail without a pause control does not ship. 44×44px. | MUST |
| <scrolled-images> theme.js:3045 |
Photo wall | Motion.ScrollOffset.Any, linear. Min 8 images per row. |
Server-render the images. NEVER INVENT CONTENT in captions. | SHOULD |
| <reveal-banner> theme.js:7902 |
Cinematic hero opener | Linear, scroll-linked. clip-path inset(20% 35% 0% 35%) → inset(0%). |
The headline must be real text under the clip, not baked art. | SHOULD |
| <split-words> <highlighted-text> |
Per-word headline reveal | 30ms per-word stagger; each word on the 1.5s [0.16,1,0.3,1] curve. |
The five scribble variants draw via strokeAnimation — specify it or they do not draw. |
SHOULD |
| <sticky-element> theme.js:3631 |
Sticky bio column | Default gap 20px, threshold 0.5px. rAF-driven, not eased. | Desktop only. Coordinate with <sticky-header>'s three thresholds. |
SHOULD |
| <number-counter> theme.js:8468 |
Stats count-up | Duration from data-duration; easing [0.16,1,0.3,1]. |
Server-render the final number as real text. NEVER INVENT CONTENT — real figures or [PLACEHOLDER]. |
SHOULD |
| <tabs-element> theme.js:7027 |
Tabbed panels | Out 0.15s (translateY 0→2rem), in 0.15s (2rem→0). |
Server-render ALL panels — tabs hide, they do not defer. | SHOULD |
| <text-scrolling> theme.js:7006 |
Scroll-told story | Opacity [0,0,1,1,1,0,0] across 33vh–66vh. |
Every heading server-rendered. Reduced motion pins opacity to 1. | SHOULD |
| <mouse-cursor> <overlay-element> |
Custom cursor | 1/4 lag factor per throttled mousemove; no fixed duration. |
Desktop / non-touch only. aria-hidden, never focusable, must not obscure the focus ring. |
COULD |
| <spinning-text> theme.js:7383 |
Circular badge | Infinite CSS rotation; in-view trigger at 600px root margin. | Decorative, aria-hidden. The wordmark must ALSO exist as real text elsewhere. |
COULD |
| <secondary-media> <secondary-video> |
Roster card hover | Pointer-position-driven, not time-based. | Touch devices show frame 1 only. No vertical lift. | COULD |
| <scroll-spy> theme.js:8968 |
In-page nav | smooth scroll; auto under reduced motion. |
Links are real anchors — must work with JS off. Offset by header height. | COULD |
| <share-drawer> theme.js:2292 |
Share this rider | Items translateY(2.5rem)→0, 0.6s on [0.075,0.82,0.165,1], 0.1s stagger, 300ms delay. |
Fallback to copy-link when navigator.share is absent. Ships fully animated. |
COULD |
| <social-feed> <social-feed-button> |
Rider social grid | Inherits modal-element — active after 75ms. |
Gate R-13 (#ad disclosure) applies to every embedded post. Arrow keys must not trap focus. |
COULD |
§ 2 — Native theme blocks (5 entries, 7 distinct blocks)
Drag-and-drop, reusable in any section that accepts blocks. None required custom Liquid.
| Block | Settings | Role | Key constraint | Tier |
|---|---|---|---|---|
| blocks/subheading | 10 | The eyebrow | The rider-page eyebrow is this block. Do not hand-roll it as a heading — that breaks the heading outline. | MUST |
| blocks/spacer | 8 | Vertical rhythm | Use instead of empty-space sections where the gap is intra-section. Never infer an --sp-* value from its name — read it. |
MUST |
| blocks/social-icons | 14 | Rider handles | Do not hand-roll; the stock block's accessible labels are the win. 24×24px minimum. | SHOULD |
| blocks/popup-link blocks/accordion blocks/_accordion-row |
14 / — / 9 | Rules modal | Structural dependency: sections/overlay-group.json decides what may sit in the overlay slot. Any giveaway popup must be registered there or it cannot be added in the theme editor. Accordion opens 0.25s ease, content fades 0.15s at −0.1s offset. |
SHOULD |
| blocks/_custom-field | 12 | Extra form fields | Every field needs a real label, not a placeholder. Focus ring #0b61cd at 2px. |
COULD |
Three keyframes families the system must specify and currently does not
LAR-1415 § D. These are load-bearing and unspecified.
| Keyframe | Timing | Why it is required |
|---|---|---|
| hotspot | 2s ease infinite | The pulsing ring on lookbook / shop-the-look hotspot markers. The Addendum-B lookbook port depends on it and it has no colour specified. |
| preloading placeholder-shimmer |
1.2s infinite ease 1.3s linear infinite |
The loading state of every image-heavy grid. Governs perceived load. Specify against #ffffff and against dark hero surfaces. |
| strokeAnimation | 1.3s cubic-bezier(0.65,0,0.35,1) forwards | SVG stroke draw-on. This is how the five scribble highlight variants DRAW. The system names the variants but never the draw-on. |
A fourth curve matters and must not be merged: fade-in is
.6s cubic-bezier(.7,0,.2,1) — a second, distinct fade curve
from the reveal engine's [0.16,1,0.3,1].
Two theme-level motion toggles gate all of the above
| Setting | Default | Why it matters |
|---|---|---|
| buttons_hover | standard | Theme-level selector deciding which hover-button behavior renders site-wide. The system's "invert on hover" rule is only reachable if this setting is right — confirm it before any button spec is signed off. |
| enable_lazy_image | true | Interacts with animate-element's wait-for-image-load. This is why cascades can stagger unevenly. |
Already named, recorded for the full picture: enable_page_transition = true — the
<loading-bar> renders on every navigation and needs a specified
colour or it renders unstyled — and enable_heading_reveal = true.
Tombstones — ours, not the theme's
Values retained in tokens.css and tombstoned in place. They must not be cited as
theme-read values.
| Token | Value | Status |
|---|---|---|
| --duration-extra-long | 600ms | Does not describe the theme's reveal engine. Ours. |
| --stagger-step | 75ms | Does not describe the theme's cascade. Superseded by 0.1s desktop / 0.05s mobile. Ours. |
| --duration-marquee | 1.5s | The theme marquee duration is computed at runtime as (33 − speed) × min(2.5, ceil(width / parentWidth)) seconds. Ours. |
| --duration-slow | 800ms | No counterpart in the theme's closure. Ours. |
| --duration-extended | 3s | 3D-lift shimmer sweep. No theme counterpart. Ours. |
| --cubic-out | cubic-bezier(0.5, 1, 0.89, 1) | No theme counterpart. Ours. |
The divergence between the two vocabularies is deliberate. The durations
agree with the theme — 200 / 300 / 500ms. The easings do not.
--ease-out-slow cubic-bezier(0,0,0.3,1) is the scroll-reveal curve
and is right for entry, but it is not what the theme runs on hover. Use the theme shorthands
for hover and --ease-out-slow for reveals; do not reconcile them by
picking one.
CANNOT-VERIFY: that these 21 entries render correctly under the SWAGTRON
settings_data.json without a build. Carried forward from LAR-1415 — candidacy is
asserted from schema and JS behaviour, not from a rendered page.