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.

theme.js:1434 (16 uses) · theme.js:4099 (17 uses) · 600ms, cubic-bezier(0,0,0.3,1), 75ms cascade

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.

theme.js:8468

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.

theme.js:1339 · 95 call sites

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.

corrected 2026-08-29, LAR-1415 · 600ms, cubic-bezier(0,0,0.3,1), 75ms

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.

theme.js:1339 · 95 call sites

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.

theme.js:8468

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.

BasisCount
Addendum C § 1 register lines (motion)16
Addendum C § 2 register lines (blocks)5
§ 1 + § 2 register lines21
Distinct JS elements named across § 122
Distinct theme blocks named across § 27
Distinct native items, § 1 + § 229
§ 1 lines (16) + § B blocks (6) + § E settings (2) — the only decomposition that lands on 2424

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)

ElementRoleMeasured timingsKey constraintTier
<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.

BlockSettingsRoleKey constraintTier
blocks/subheading10The eyebrow The rider-page eyebrow is this block. Do not hand-roll it as a heading — that breaks the heading outline. MUST
blocks/spacer8Vertical 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-icons14Rider 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 / — / 9Rules 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-field12Extra 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.

KeyframeTimingWhy it is required
hotspot2s 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

SettingDefaultWhy it matters
buttons_hoverstandard 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_imagetrue 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.

TokenValueStatus
--duration-extra-long600ms Does not describe the theme's reveal engine. Ours.
--stagger-step75ms Does not describe the theme's cascade. Superseded by 0.1s desktop / 0.05s mobile. Ours.
--duration-marquee1.5s The theme marquee duration is computed at runtime as (33 − speed) × min(2.5, ceil(width / parentWidth)) seconds. Ours.
--duration-slow800ms No counterpart in the theme's closure. Ours.
--duration-extended3s 3D-lift shimmer sweep. No theme counterpart. Ours.
--cubic-outcubic-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.