Scroll effects hub: 64 original verbatim versions (freefrontend/CodePen, MIT) in Rheinmir/uiux-asset — browse the gallery, copy the file as-is. Plus 7 hand-written vanilla effects in assets/ for projects that can't pull in external libs.
WHAT
Purpose and context
- Purpose: attach lightweight scroll effects to the target page — by default copy the ORIGINAL file as-is from
Rheinmir/uiux-asset; for projects that can't pull in external libs, use the 7 vanilla patterns inassets/. - Trigger (when to use):
- Page needs fade-in-on-scroll effects, staggered text, eye-guiding highlights, shrinking nav, back-to-top button, a table of contents that sticks to sections, or light parallax.
- User says "scroll effects", "scroll to top", "scrollspy", "parallax", "reveal on scroll".
- Non-goals: NOT used for: heavy GPU cinematic image transitions (that's
blur), timeline milestone axes (that'stimeline), complex GSAP ScrollTrigger-style horizontal pin-section scrolling (beyond the scope of this lightweight skill — say so clearly to the user).
Mental model
nhu cầu hiệu ứng → gallery 64 bản gốc (mặc định, copy nguyên file) hoặc 7 pattern vanilla (không được kéo lib) → adapt token theo design.md → một IntersectionObserver + một scroll listener rAF → reduced-motion tắt hết → verify playwright. The hub branches to the corresponding sub-skill when a gallery item belongs to a sub-skill.
Input and output contract
| Field | Required? | Meaning | |
|---|---|---|---|
| In | effect needed | yes | one of the 7 patterns or a gallery item |
| In | project constraints | no | whether external libs/files can be pulled in; whether design.md is allowed |
| Out | effect file in the project | yes | original copied as-is (keep the attribution comment on the first line) or adapted vanilla asset |
| Out | verification evidence | yes | before/after scroll screenshots, .is-in appears, no horizontal overflow |
Rules and capabilities
- RULE-01 (MUST):
prefers-reduced-motion: reduce→ disable everything: CSS forces.is-into appear immediately with no transition, JS drops smooth scroll and parallax (already coded in the assets, don't remove this branch when adapting). - RULE-02 (MUST): One
IntersectionObservershared for reveal + stagger + highlight + TOC (already merged inscroll-effects.js) — don't create 4 separate observers. - RULE-03 (MUST): Single scroll listener, rAF-throttled — nav + top + parallax all read one shared
scrollYeach frame, don't attach 3 separatescrolllisteners. - RULE-04 (MUST): Verify with
playwright-verify: capture before/after scroll, assert.is-inappears, measure that there's no horizontal overflow from parallax. - RULE-05 (MUST): When adapting into a project that has
design.md: change color/spacing tokens, keep the namesdata-se-*(JS relies on them). - Capabilities: read external gallery/repo assets (network) or internal assets; write project front-end files; run headless browser over local HTTP.
Failure boundaries
- The request is heavy WebGL, milestone timeline, or complex GSAP pin-section → blocked out of scope, state it clearly to the user and point to the right skill.
- Cannot access external gallery/repo or the project forbids external libs → use the 7 vanilla patterns (not an error).
- Playwright verify does not see
.is-inor there is horizontal overflow → failed, fix then verify again.
HOW
Main workflow
| Step | Type | Inputs | Action | Outputs/exit | Failure/next |
|---|---|---|---|---|---|
| W01 | judgment | request | Match scope (not blur/timeline/GSAP pin) | effect in scope | out of scope → blocked |
| W02 | judgment | project constraints | Choose source: original gallery (default) or vanilla assets/ (B01) |
source | — |
| W03 | effect | source | Original: open the running link → copy the whole .html (+ _assets/) → keep the attribution comment → only edit content/images/colors |
file in project | — |
| W04 | effect | design.md |
Adapt color/spacing tokens, keep data-se-*, keep the reduced-motion branch |
adapted file | — |
| W05 | deterministic | page over HTTP | playwright-verify: capture before/after scroll, assert .is-in, measure overflow |
PASS | FAIL → fix, repeat W05 |
Details of each step (source of truth for W01–W05):
Original — use FIRST (copy the whole file, do not rewrite)
The author's ORIGINAL VERBATIM code (public CodePen = MIT) is in the external repo Rheinmir/uiux-asset — real running gallery: https://rheinmir.github.io/uiux-asset/scroll-effects/ .
Process: open the link run to see the exact effect → copy the whole file .html (+ folder _assets/ if the file references it) into the project → keep the attribution comment on the first line → only edit content/images/colors. Run locally over HTTP, not file://.
git clone --depth 1 https://github.com/Rheinmir/uiux-asset if the whole offline set is needed.
Hub: browse all 64 entries in the gallery (filter by name/technique/author), then branch to the corresponding child skill.
assets/ in this skill is only a condensed self-written vanilla version — use it when the project must NOT pull external libs; by default use the original above.
Assets
assets/demo.html (pre-assembled demo page with all 7) + assets/scroll-effects.css + assets/scroll-effects.js — read then ADAPT (change class/token per design.md of the project if any).
Branches
| ID | Kind | Guard | Behavior | Skip / failure | Rejoin |
|---|---|---|---|---|---|
| B01 | conditional_required | the project is NOT allowed to pull external lib/file | use the 7 vanilla patterns in assets/ (Reference section below) instead of the original version |
allowed to pull external → original gallery version | W04 |
| B02 | user_optional | needs the whole original set offline | git clone --depth 1 repo Rheinmir/uiux-asset |
— | W03 |
| B03 | conditional_required | gallery item belongs to a sub-skill | branch to the corresponding sub-skill | — | ends at the sub-skill |
Validation and stopping
Run over local HTTP (no file://). PASS when playwright captures before/after scroll and sees .is-in, no horizontal overflow, and with reduced-motion every element appears immediately. Stop when PASS; on FAIL, fix and verify again.
Examples
- Positive: "add scroll to top + scrollspy for the docs page, no pulling libs allowed" → B01 uses
[data-se-top]+[data-se-toc]fromassets/, change token perdesign.md, keepdata-se-*→ playwright: button appears whenscrollY > innerHeight, TOC link receives.is-active. - Boundary/failure: "make a horizontal scroll-pinned section GSAP style" → outside the scope of this lightweight skill → tell the user clearly, do not try to build it with parallax
data-se-parallax.
Reference — 7 patterns (minimal markup + mechanism)
1. Reveal on scroll — [data-se-reveal]
Element faded + slides slightly, appears when scrolled into viewport.
<div data-se-reveal>Lộ dần khi cuộn tới</div>
IntersectionObserver attach .is-in → CSS transition opacity/translateY. Refer to gallery scroll-effects #9 (Animated Scroll Highlight Annotations) for use cases, do not use their code.
2. Staggered text — [data-se-stagger]
Lines of text appear one after another.
<h2 data-se-stagger>
<span>Dòng một</span><span>Dòng hai</span><span>Dòng ba</span>
</h2>
JS assigns --i to each span → CSS transition-delay: calc(var(--i) * 90ms). Only split by existing child elements, do not split text nodes yourself (keep DOM simple, avoid a11y issues).
3. Scroll highlight — [data-se-highlight] > mark
Highlight key points, color streak sweeps left→right when the paragraph enters the viewport.
<p data-se-highlight>Đọc tới đây <mark>ý chính hiện ra</mark> rồi đọc tiếp.</p>
mark use background-size: 0% → 100% transition when parent has .is-in. Use <mark> real semantics, not fake span.
4. Sticky shrink nav — [data-se-nav]
Header shrinks when scrolling down, expands back when at the top.
<header data-se-nav class="site-nav">…</header>
Scroll listener (rAF-throttle) toggle .is-shrunk when scrollY > 24. Only change padding/font-size via class, do not set inline style every frame.
5. Scroll to top — [data-se-top]
Back-to-top button, only appears after scrolling past one screen.
<button data-se-top aria-label="Về đầu trang">↑</button>
Click → window.scrollTo({ top: 0, behavior: "smooth" }) (unless prefers-reduced-motion → "auto"). Show threshold: scrollY > innerHeight.
6. Scrollspy TOC — [data-se-toc] a[href^="#"] + section[id]
Sticky table of contents, link highlights according to the section being read.
<nav data-se-toc><a href="#s1">Mục 1</a><a href="#s2">Mục 2</a></nav>
<section id="s1">…</section><section id="s2">…</section>
IntersectionObserver with rootMargin: "-40% 0px -55% 0px" → matching link receives .is-active. See gallery #19 (Auto-Generated Anchor TOC) for the idea, code written by ourselves.
7. Light parallax — [data-se-parallax="0.2"]
Content layer drifts slower/faster than scroll speed.
<div data-se-parallax="0.15">Trôi chậm tạo chiều sâu</div>
rAF loop: translateY = (elCenter - viewportCenter) * speed. Value speed recommended |v| ≤ 0.3; exceeding it causes motion sickness. DO NOT use for small text that needs to be read precisely.
Origin
- User decided "just do it, too many questions" → instead of bulk-copying 81 works, write an ORIGINAL SET of 7 generic patterns (industry-standard techniques: IntersectionObserver/scroll listener/rAF — not anyone's own creative expression) so downstream can reference sample code immediately, the right way
blur/timelinedid.