Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build reversible scroll-controlled visual transformations with a pinned or sticky stage, normalized progress, and video, image-sequence, canvas, SVG, or DOM renderers. Use for hero transformations, product assembly, interface state walkthroughs, object rotation, diagrams, or photo sequences that must move forward and backward with native scrolling.
.claude/skills/mengto-scroll-scrubbed-visual-sequence/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 15% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 4% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 18% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 24% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 17% | 0% |
Turn one visual transformation into a responsive scroll instrument. Keep the page usable without motion and keep the renderer replaceable.
Write the visual states before coding:
jsconst sequence = { scrollVh: 280, frameCount: 96, fit: "contain", posterFrame: 0, reducedMotionFrame: 95, copyStops: [0, 0.42, 0.78] };
Use one normalized value for every renderer:
jsconst progress = Math.min(1, Math.max(0, (viewportTop - sectionTop) / (sectionHeight - viewportHeight) ));
Never make wheel delta, elapsed time, or autoplay the source of truth. Native scroll position must determine the exact visual state in both directions.
currentTime writes in requestAnimationFrame.scrollVh.position: sticky stage sized to the viewport.Use GSAP ScrollTrigger when the project already uses GSAP or needs exact pin, refresh, and timeline coordination:
jsScrollTrigger.create({ trigger: section, start: "top top", end: () => `+=${innerHeight * 2.8}`, pin: stage, scrub: true, invalidateOnRefresh: true, onUpdate: ({ progress }) => render(progress) });
For a dependency-free implementation, measure the section on scroll and resize, then schedule one render per animation frame.
0...frameCount - 1.object-fit and an explicit focal point so the subject survives mobile crops.prefers-reduced-motion: reduce, remove pinning and scrubbing, render the selected static frame, and restore ordinary document flow.Expose scroll distance, renderer, frame count, poster frame, media fit, focal point, copy stops, overlay strength, smoothing, and reduced-motion state as configuration. Avoid magic numbers distributed across event handlers.
Check forward and reverse scrolling, fast flicks, resize while active, 390/768/1024/1440 widths, unloaded frames, blocked video, reduced motion, keyboard order, route cleanup, and console errors. The same scroll position must always reproduce the same state.
Use demo/index.html as the working reference and demo/PROMPT.md to recreate or remix it. Keep REFERENCES.md as the links-only implementation source list.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 28,774 | 27,722 | -4% | 1 | 1 | 0% | 6,192 | 7,128 | +15% | 0 | 0 | — |
case-02 | fail→fail | 24,050 | 26,153 | +9% | 1 | 1 | 0% | 5,666 | 7,114 | +26% | 0 | 0 | — |
case-03 | fail→pass | 31,645 | 25,749 | -19% | 1 | 1 | 0% | 6,216 | 6,453 | +4% | 0 | 0 | — |
case-04 | pass→pass | 15,253 | 10,846 | -29% | 1 | 1 | 0% | 3,248 | 3,181 | -2% | 0 | 0 | — |
case-05 | pass→pass | 20,904 | 23,471 | +12% | 1 | 1 | 0% | 4,045 | 5,922 | +46% | 0 | 0 | — |
case-14 | fail→fail | 14,556 | 17,141 | +18% | 1 | 1 | 0% | 3,123 | 4,614 | +48% | 0 | 0 | — |
case-06 | pass→pass | 16,793 | 15,232 | -9% | 1 | 1 | 0% | 3,024 | 3,964 | +31% | 0 | 0 | — |
case-07 | fail→pass | 15,175 | 12,806 | -16% | 1 | 1 | 0% | 2,982 | 3,508 | +18% | 0 | 0 | — |
case-08 | pass→pass | 16,260 | 11,299 | -31% | 1 | 1 | 0% | 3,011 | 3,107 | +3% | 0 | 0 | — |
case-09 | pass→fail | 12,620 | 10,973 | -13% | 1 | 1 | 0% | 2,538 | 3,091 | +22% | 0 | 0 | — |
case-10 | pass→pass | 11,661 | 7,699 | -34% | 1 | 1 | 0% | 1,990 | 2,338 | +17% | 0 | 0 | — |
case-11 | pass→pass | 9,549 | 12,220 | +28% | 1 | 1 | 0% | 1,952 | 3,584 | +84% | 0 | 0 | — |
case-12 | pass→pass | 12,852 | 7,847 | -39% | 1 | 1 | 0% | 2,724 | 2,669 | -2% | 0 | 0 | — |
case-13 | pass→pass | 14,617 | 14,089 | -4% | 1 | 1 | 0% | 2,523 | 3,672 | +46% | 0 | 0 | — |
case-15 | pass→pass | 13,770 | 9,485 | -31% | 1 | 1 | 0% | 2,811 | 2,878 | +2% | 0 | 0 | — |
case-16 | fail→pass | 10,666 | 6,732 | -37% | 1 | 1 | 0% | 1,817 | 2,245 | +24% | 0 | 0 | — |
case-17 | fail→pass | 14,624 | 10,090 | -31% | 1 | 1 | 0% | 2,589 | 3,031 | +17% | 0 | 0 | — |
case-18 | pass→pass | 13,813 | 11,141 | -19% | 1 | 1 | 0% | 2,258 | 2,941 | +30% | 0 | 0 | — |
case-19 | fail→pass | 17,240 | 11,509 | -33% | 1 | 1 | 0% | 2,822 | 2,972 | +5% | 0 | 0 | — |
case-20 | pass→pass | 18,193 | 12,971 | -29% | 1 | 1 | 0% | 3,143 | 3,211 | +2% | 0 | 0 | — |
case-21 | pass→pass | 16,243 | 11,271 | -31% | 1 | 1 | 0% | 2,827 | 3,244 | +15% | 0 | 0 | — |
case-22 | pass→pass | 18,079 | 17,268 | -4% | 1 | 1 | 0% | 3,091 | 4,257 | +38% | 0 | 0 | — |
case-23 | pass→pass | 13,135 | 22,136 | +69% | 1 | 1 | 0% | 2,899 | 5,995 | +107% | 0 | 0 | — |
case-24 | pass→pass | 7,021 | 9,925 | +41% | 1 | 1 | 0% | 1,547 | 3,168 | +105% | 0 | 0 | — |
case-25 | pass→pass | 14,196 | 17,842 | +26% | 1 | 1 | 0% | 2,994 | 4,923 | +64% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted. The headline lift of +20 percentage points is the difference between those two pass rates over the 25 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.